我不能使用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
调用成功且信息结构正常,但对SetPrinter
的调用失败。
有趣的是,当我忽略SetPrinter
的结果时,即使SetPrinter
失败,打印对话框也会将A4报告为打印机尺寸。
我是否完全错误,将PDeviceMode正确设置为OpenPrinter就足够了? (在写完这个问题后,我实际想出了这个: - )
关于VCL的另一个问题:
如果我使用Printers
单位,我怎么知道缓冲区必须有多大才能作为参数传递给TPrinter.GetPrinter
方法?
背景:
系统为:Windows 7 Professional 64位英语语言环境。
我正在尝试在网络打印机(Brother HL-5350DN)上打印到A4纸。
我已将控制面板中的所有打印机设置都设置为A4纸张,但我正在编写的Delphi 2009程序仍然可以获得US Letter的纸张尺寸。
换句话说:Delphi程序不尊重打印机假脱机程序的默认设置。
如果我先运行TPrinterDialog并从那里手动选择正确的纸张尺寸(在高级打印机设置中),一切都很好。
该程序必须在没有任何UI的情况下运行,因此我必须以编程方式解决此问题,或者最好是程序应该尊重默认的Windows打印机假脱机程序设置。
也许我错过了一些令人讨厌的环境?
答案 0 :(得分:7)
试试这个家伙 它对我有用
uses WinSpool,Windows,System;
procedure SetPrinterInfo(APrinterName: PChar);
var
HPrinter : THandle;
InfoSize,
BytesNeeded: Cardinal;
DevMode : PDeviceMode;
PI2: PPrinterInfo2;
PrinterDefaults: TPrinterDefaults;
begin
with PrinterDefaults do
begin
DesiredAccess := PRINTER_ACCESS_USE;
pDatatype := nil;
pDevMode := nil;
end;
if OpenPrinter(APrinterName, HPrinter, @PrinterDefaults) then
try
SetLastError(0);
//Determine the number of bytes to allocate for the PRINTER_INFO_2 construct...
if not GetPrinter(HPrinter, 2, nil, 0, @BytesNeeded) then
begin
//Allocate memory space for the PRINTER_INFO_2 pointer (PrinterInfo2)...
PI2 := AllocMem(BytesNeeded);
try
InfoSize := SizeOf(TPrinterInfo2);
if GetPrinter(HPrinter, 2, PI2, BytesNeeded, @BytesNeeded) then
begin
DevMode := PI2.pDevMode;
DevMode.dmFields := DevMode.dmFields or DM_PAPERSIZE;
DevMode.dmPaperSize := DMPAPER_A4;
PI2.pSecurityDescriptor := nil;
// Apply settings to the printer
if DocumentProperties(0, hPrinter, APrinterName, PI2.pDevMode^,
PI2.pDevMode^, DM_IN_BUFFER or DM_OUT_BUFFER) = IDOK then
begin
SetPrinter(HPrinter, 2, PI2, 0); // Ignore the result of this call...
end;
end;
finally
FreeMem(PI2, BytesNeeded);
end;
end;
finally
ClosePrinter(HPrinter);
end;
end;
答案 1 :(得分:1)
像大卫写的那样,通过在Windows中设置正确的打印机首选项来解决我的具体问题。
我仍然没有找到为我的应用程序设置本地打印属性的方法,但现在不再需要了。
与Sertac一样,您可以使用TPrinter.GetPrinter
和TPrinter.SetPrinter
来读取和编写全局打印机首选项。 (见问题评论)
由于没有人提供anwser并且问题现在已经解决,我将此标记为社区维基。随意改进这个答案。