如何使用WinSpool API设置纸张尺寸?
我无法使用 XPS API,因为该程序必须能够在 Windows XP 上打印。
我正在尝试使用 WinSpool 将纸张尺寸从 Letter 设置为 A4。
这是我的测试代码:
var
H : THandle;
I : TBytes;
Info : PPrinterInfo2;
NeededSize : DWORD;
DevMode : PDeviceMode;
PD : TPrinterDefaults;
begin
PD.pDatatype := nil;
PD.pDevMode := nil;
PD.DesiredAccess := PRINTER_ACCESS_ADMINISTER;
if not OpenPrinter('Brother HL-5350DN series Printer', H, @PD) then begin
raise Exception.Create('OpenPrinter error: ' + SysErrorMessage(GetLastError));
end;
try
Assert(not GetPrinter(H, 2, nil, 0, @NeededSize));
SetLength(I, NeededSize);
Info := @I[0];
if not GetPrinter(H, 2, Info, NeededSize, @NeededSize) then begin
raise Exception.Create('GetPrinter error: ' + SysErrorMessage(GetLastError));
end;
DevMode := Info.pDevMode;
DevMode.dmFields := DevMode.dmFields or DM_PAPERSIZE;
DevMode.dmPaperSize := DMPAPER_A4;
Info.pSecurityDescriptor := nil; // According to MSDN it has to be niled if we're not going to change it.
if not SetPrinter(H, 2, Info, 0) then begin
raise Exception.Create('SetPrinter error: ' + SysErrorMessage(GetLastError));
end;
finally
ClosePrinter(H);
end;
TPrintDialog.Create(Self).Execute; // This is just so I can check the paper size
end;
我有两个与访问权限相关的问题。
如果我将 PD.DesiredAccess
设置为 PRINTER_ACCESS_ADMINISTER
,则 GetPrinter
调用失败,我猜这是由于 UAC 造成的。
如果我将其设置为 PRINTER_ACCESS_USE ,则 GetPrinter 调用成功并且 Info 结构正常,但对 SetPrinter 的调用失败。
有趣的是,当我忽略 SetPrinter
的结果时,即使 SetPrinter
失败,打印对话框也会将 A4 报告为打印机尺寸。
我这样做是否完全错误,并且将正确设置的 PDeviceMode 传递给 OpenPrinter 就足够了? (我实际上是在写完这个问题后想到的:-)
关于VCL的另一个问题:
如果我使用Printers
单元,我如何知道作为参数传递给的缓冲区必须有多大TPrinter.GetPrinter
方法?
背景:
系统为:Windows 7 Professional 64-Bit English,语言环境为英语。
我正在尝试在网络打印机(Brother HL-5350DN)上打印到 A4 纸。
我已将控制面板中的所有打印机设置设置为 A4 纸张,但我正在编写的 Delphi 2009 程序仍然获取 US Letter 的纸张尺寸。
换句话说:Delphi 程序不尊重打印机后台处理程序的默认设置。
如果我首先运行 TPrinterDialog 并从那里手动选择正确的纸张尺寸(在高级打印机设置中),一切都会很好。
该程序必须在没有任何 UI 的情况下运行,因此我必须以编程方式解决此问题,或者最好该程序应该遵循默认的 Windows 打印机后台处理程序设置。
也许我错过了一些重要的设置?
I can't use the XPS API since the program has to be able to print on Windows XP.
I'm trying to set the paper size from Letter to A4 using WinSpool.
This is my test code:
var
H : THandle;
I : TBytes;
Info : PPrinterInfo2;
NeededSize : DWORD;
DevMode : PDeviceMode;
PD : TPrinterDefaults;
begin
PD.pDatatype := nil;
PD.pDevMode := nil;
PD.DesiredAccess := PRINTER_ACCESS_ADMINISTER;
if not OpenPrinter('Brother HL-5350DN series Printer', H, @PD) then begin
raise Exception.Create('OpenPrinter error: ' + SysErrorMessage(GetLastError));
end;
try
Assert(not GetPrinter(H, 2, nil, 0, @NeededSize));
SetLength(I, NeededSize);
Info := @I[0];
if not GetPrinter(H, 2, Info, NeededSize, @NeededSize) then begin
raise Exception.Create('GetPrinter error: ' + SysErrorMessage(GetLastError));
end;
DevMode := Info.pDevMode;
DevMode.dmFields := DevMode.dmFields or DM_PAPERSIZE;
DevMode.dmPaperSize := DMPAPER_A4;
Info.pSecurityDescriptor := nil; // According to MSDN it has to be niled if we're not going to change it.
if not SetPrinter(H, 2, Info, 0) then begin
raise Exception.Create('SetPrinter error: ' + SysErrorMessage(GetLastError));
end;
finally
ClosePrinter(H);
end;
TPrintDialog.Create(Self).Execute; // This is just so I can check the paper size
end;
I have two problems related to access rights.
If I set PD.DesiredAccess
to PRINTER_ACCESS_ADMINISTER
the GetPrinter
call fails, I guess this is due to UAC.
If I set it to PRINTER_ACCESS_USE
the GetPrinter
call succeeds and the Info structure is fine, but the call to SetPrinter
fails.
Interestingly enough when I ignore the Result of SetPrinter
the print dialog reports A4 as the printer size even though SetPrinter
fails.
Am I doing it completly wrong and it is enough to pass a correctly setup up PDeviceMode to OpenPrinter? (I actually came up with this after writing this question :-)
Another question regarding the VCL:
If I use the Printers
unit how do I know how big the buffers have to be that get passed as parameters to the TPrinter.GetPrinter
method?
Background:
The system is: Windows 7 Professional 64-Bit English with English locale.
I'm trying to print to A4 paper on a network printer (Brother HL-5350DN).
I have set all printer settings in the control panel to A4 paper, but the Delphi 2009 program I'm writing still gets the paper dimensions for US Letter.
In other words: The Delphi program doesn't respect the default settings of the printer spooler.
If I run a TPrinterDialog first and select the correct paper size from there manually (in the advanced printer settings) everything is fine.
The program has to run without any UI, so I have to solve this programmatically or preferably the program should just respect the default Windows printer spooler settings.
Maybe I have missed some imporant setting?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
试试这个家伙
它对我有用
try this guys
it work for me
正如 David 所写,我的具体问题是通过在 Windows 中设置正确的打印机首选项来解决的。
我仍然没有找到为我的应用程序设置本地打印属性的方法,但这不再是必要的。
正如 Sertac 所写,您可以使用
TPrinter.GetPrinter
和TPrinter.SetPrinter
读取和写入全局打印机首选项。 (请参阅问题的评论)由于没有人提供答案并且问题现已解决,我将其标记为社区维基。请随意改进这个答案。
Like David wrote, my specific problem is solved by setting the correct printer preferences in Windows.
I still haven't found a way to set the local printing properties for my application, but that is no longer necessary.
Like Sertac wrote you can read and write the global printer preferences using
TPrinter.GetPrinter
andTPrinter.SetPrinter
. (See the comments to the question)Since nobody provided an anwser and the problem is now solved, I'm marking this as community wiki. Feel free to improve this answer.