在Windows 10上使用ERROR_NOT_SUPPORTED打印机CreateDC/CreateIC失败

Ian*_*oyd 5 printing winapi windows-10

我试图打电话CreateDC来创建一个打印机设备上下文:

printerDC := CreateDC('WINSPOOL', 'HP DeskJet 930C/932C/935C', nil, nil);
Run Code Online (Sandbox Code Playgroud)

该代码适用于Windows 7,但在Windows 10中失败 - 返回null.

我真的在使用真正的打印机:

在此输入图像描述

什么通过

MSDN文档说,如果你想获得打印机设备上下文,你必须通过WINSPOOL作为驱动:

如何:检索打印机设备上下文

要渲染到特定打印机,必须将"WINSPOOL"指定为设备,并将正确的打印机名称传递给CreateDC.如果要在创建设备上下文时为设备驱动程序提供特定于设备的初始化数据,也可以在调用CreateDC时传递DEVMODE结构.

以下示例显示了对CreateDC的调用,其中选择了"WINSPOOL"驱动程序,并且按名称指定了打印机名称.C++

printerDC = CreateDC( L"WINSPOOL", printerName, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)

我提到它,因为有很多代码通过:

  • 空字符串
  • 空值
  • 设备的名称
  • 驱动程序的名称
  • winspool
  • WINSPOOL

背景

深入Delphi VCL框架Vcl.Printers是对Windows功能的调用CreateIC.在我的Windows 10桌面上,调用失败(返回NULL而不是有效的信息上下文).

CreateIC功能不记录任何失败的方式.它也没有记录它支持调用GetLastError以获取错误.但如果我打电话给GetLastError我得到错误代码50:

ERROR_NOT_SUPPORTED  
50 (0x32)  
The request is not supported.  
Run Code Online (Sandbox Code Playgroud)

最低可重复性

我从Vcl.Printers.pas中提取代码并将其煮成一个简单的可重复样本:

procedure TForm1.Button1Click(Sender: TObject);
var
    driver, device, output: string;
    dc: HDC;
    le: DWORD;
begin
    driver := '';
    device := 'Microsoft XPS Document Writer';
    output := '';

    dc := CreateIC(PChar(driver), PChar(device), PChar(output), nil);
    if dc = 0 then
    begin
        le := GetLastError;
        raise Exception.CreateFmt('Could not get information context for printer "%s": %s (%d)', [device, SysErrorMessage(le), le]);
    end;
end;    
Run Code Online (Sandbox Code Playgroud)

代码在我的Windows 10桌面上失败,但适用于Windows 7.

在这两种情况下我都使用相同的打印机:

  • Windows 7的

    在此输入图像描述

  • Windows 10 在此输入图像描述

我是什么1做错了什么?

CreateDC也失败了

CreateIC它只是一种"轻量级"形式CreateDC(你可以用它来获取有关设备的信息,但你无法用它绘制GDI).这也意味着CreateDC在Windows 10上也会失败:

procedure TForm1.Button1Click(Sender: TObject);
var
    driver, device: string;
    dc: HDC;
    le: DWORD;
begin
    driver := '';
    device := 'Microsoft XPS Document Writer';

    dc := CreateDC(PChar(driver), PChar(device), nil, nil);
    if dc = 0 then
    begin
        le := GetLastError;
        raise Exception.CreateFmt('Could not get device context for printer "%s": %s (%d)', [device, SysErrorMessage(le), le]);
    end;
end;    
Run Code Online (Sandbox Code Playgroud)

一些人已经提出重复设备名称到驱动程序名称:

CreateDC('Microsoft XPS Document Writer', 'Microsoft XPS Document Writer', nil, nil);
Run Code Online (Sandbox Code Playgroud)

也看到尝试放入 WINSPOOL驱动程序名称:

CreateDC('WINSPOOL', 'Microsoft XPS Document Writer', nil, nil);
Run Code Online (Sandbox Code Playgroud)

这都是打印机

我开始这个问题,认为它只是CreateIC.

  • 然后我发现CreateDC也失败了,所以我更新了标题
  • 然后我认为这是因为我碰巧使用的是Microsoft XPS Document Writer,所以我更新了标题
  • 然后我发现它是Windows 10上的所有打印机,所以我再次更新了标题

这是人们提出建议的自然演变,我发现了更多关于问题本质的东西.

| Driver                             | Device                          | Result |
|------------------------------------|---------------------------------|--------|
| '' (empty string)                  | 'Microsoft XPS Document Writer' | Fails  |
| 'Microsoft XPS Document Writer'    | 'Microsoft XPS Document Writer' | Fails  |
| 'WINSPOOL'                         | 'Microsoft XPS Document Writer' | Fails  |
| nil                                | 'Microsoft XPS Document Writer' | Fails  |
| 'Microsoft XPS Document Writer v4' | 'Microsoft XPS Document Writer' | Fails  |
| '' (empty string)                  | 'HP DeskJet 930C/932C/935C'     | Fails  |
| 'HP DeskJet 930C/932C/935C'        | 'HP DeskJet 930C/932C/935C'     | Fails  |
| 'WINSPOOL'                         | 'HP DeskJet 930C/932C/935C'     | Fails  |
| nil                                | 'HP DeskJet 930C/932C/935C'     | Fails  |
Run Code Online (Sandbox Code Playgroud)

据我所知,在Windows 10中也打破了CreateDC创建显示设备上下文的问题.就像你一样,我没有测试它.

奖金阅读

1不是我; Embarcadero公司