我为Windows' print spooler APIs编写了包装类,主要用于...
不工作的唯一方法是应用打印机设置。
首先,我致电DocumentProperties()成功获取并使用打印机设置。
然后我尝试使用ResetDC()应用这些设置,但没有任何反应。 该函数采用有效句柄,并返回相同的有效句柄,这意味着它应该应用了这些设置。 但是,似乎没有发生任何事情:打印输出不受打印机设置更改的影响。
我甚至尝试将SetPrinter()与level 9一起使用,也没有效果。
这项任务变得相当紧迫。有什么建议吗?
使用Delphi XE2,Windows 7 64位。
好的,跳过所有大量的OO包装器。这是一个精简的程序版本。 (请注意,您必须为其提供XPS文件。)
正在应用打印机设置更改 (使用Info2_Apply()时),可以在MS Word中看到。 它们只是在打印时被忽略。这就是谜。
我尝试了很多东西,但是我的选择已经用完了。帮助将是......非常感激。
我终于用完了选项。
这是我的测试代码的最后一个版本。它是自包含的并且包含比你需要的更多的功能 - 这是我想到的任何想法的结果。
如果其他人可以让打印机设置正常工作,请您告诉我?
使用以下命令填充带有打印机名称的组合框:
uses
Printers
ComboBox1.Items.Assign(Printer.Printers);
打印程序(我的测试代码):
uses
Winapi.WinSpool
procedure PrintXPS(PrinterName, FileNameXPS: string; ParentFormHandle: THandle = 0);
// Printer handle
procedure Printer_Open(out Printer: THandle; Defaults: PPrinterDefaultsW = nil);
begin
if not OpenPrinterW(PWideChar(PrinterName), Printer, Defaults) then
RaiseLastOSError;
end;
procedure Printer_Close(Printer: THandle);
begin
if not ClosePrinter(Printer) then
RaiseLastOSError;
end;
// Printer defaults
procedure Defaults_Obtain(out DefaultsHandle: THandle; out Defaults: PPrinterDefaultsW);
begin
DefaultsHandle := GlobalAlloc(GHND, SizeOf(TPrinterDefaultsW));
if DefaultsHandle = 0 then
RaiseLastOSError;
Defaults := GlobalLock(DefaultsHandle);
if Defaults = nil then
RaiseLastOSError;
end;
// Print settings
procedure Settings_Obtain(Printer: THandle; out SettingsHandle: THandle; out Settings: PDeviceModeW);
var
DeviceModeSize: integer;
begin
DeviceModeSize := DocumentProperties(0, Printer, PWideChar(PrinterName), nil, nil, 0);
if DeviceModeSize < 0 then
RaiseLastOSError;
// Allocate memory
SettingsHandle := GlobalAlloc(GHND, DeviceModeSize);
if SettingsHandle = 0 then
RaiseLastOSError;
// Lock memory
Settings := GlobalLock(SettingsHandle);
if Settings = nil then
RaiseLastOSError;
// Populate memory
if DocumentProperties(ParentFormHandle, Printer, PWideChar(PrinterName), Settings, Settings, DM_OUT_BUFFER) < 0 then
RaiseLastOSError;
end;
procedure Settings_Show(Printer: THandle; var Settings: PDeviceModeW; Options: Cardinal);
var
Return: integer;
begin
Return := DocumentProperties(ParentFormHandle, Printer, PWideChar(PrinterName), Settings, Settings, Options);
if Return < 0 then
RaiseLastOSError;
end;
// DC
function ObtainDC(Printer: THandle; DeviceMode: PDeviceModeW): HDC;
begin
Result := CreateDC(nil, PWideChar(PrinterName), nil, DeviceMode);
if Result = 0 then
RaiseLastOSError;
end;
procedure ApplyDC(DC: HDC; DeviceMode: PDeviceModeW);
begin
if ResetDC(DC, DeviceMode^) = 0 then
RaiseLastOSError;
end;
// PRINTER_INFO_2
procedure Info2_Obtain(Printer: THandle; out Info2Handle: THandle; out Info2: PPrinterInfo2W);
var
InfoSize: Cardinal;
begin
GetPrinterW(Printer, 2, nil, 0, @InfoSize);
// Get printer info memory
Info2Handle := GlobalAlloc(GHND, InfoSize);
if Info2Handle = 0 then
RaiseLastOSError;
// Lock printer info memory
Info2 := GlobalLock(Info2Handle);
if Info2 = nil then
RaiseLastOSError;
// Get printer info data
if not GetPrinterW(Printer, 2, Info2, InfoSize, @InfoSize) then
RaiseLastOSError;
end;
procedure Info2_Apply(Printer: THandle; Info2: PPrinterInfo2W);
begin
if not SetPrinterW(Printer, 2, Info2, 0) then
RaiseLastOSError;
end;
// PRINTER_INFO_8
procedure Info8_Fetch(Printer: THandle; Settings: PDeviceModeW);
var
lBuffer: PPrinterInfo8W;
lBufferSize: Cardinal;
begin
GetPrinterW(Printer, 8, nil, 0, @lBufferSize);
GetMem(lBuffer, lBufferSize);
try
FillChar(lBuffer^, lBufferSize, 0);
// Make the call
lBuffer.pDevMode := Settings;
if not GetPrinterW(Printer, 8, lBuffer, lBufferSize, @lBufferSize) then
RaiseLastOSError;
finally
FreeMem(lBuffer, lBufferSize);
end;
end;
procedure Info8_Apply(Printer: THandle; Settings: PDeviceModeW);
var
lPrinterInfo8: TPrinterInfo8W;
begin
lPrinterInfo8.pDevMode := Settings;
if not SetPrinterW(Printer, 8, @lPrinterInfo8, 0) then
RaiseLastOSError;
end;
// PRINTER_INFO_9
procedure Info9_Fetch(Printer: THandle; Settings: PDeviceModeW);
var
lBuffer: PPrinterInfo9W;
lBufferSize: Cardinal;
begin
GetPrinterW(Printer, 9, nil, 0, @lBufferSize);
GetMem(lBuffer, lBufferSize);
try
FillChar(lBuffer^, lBufferSize, 0);
// Make the call
lBuffer.pDevMode := Settings;
if not GetPrinterW(Printer, 9, lBuffer, lBufferSize, @lBufferSize) then
RaiseLastOSError;
finally
FreeMem(lBuffer, lBufferSize);
end;
end;
procedure Info9_Apply(Printer: THandle; Settings: PDeviceModeW);
var
lPrinterInfo9: TPrinterInfo9W;
begin
lPrinterInfo9.pDevMode := Settings;
if not SetPrinterW(Printer, 9, @lPrinterInfo9, 0) then
RaiseLastOSError;
end;
// Print jobs
function JobCreate(Printer: THandle; FileName: string): Cardinal;
var
lBufferSize: Cardinal;
lAddJobInfo: PAddJobInfo1W;
begin
// Create job
AddJobW(Printer, 1, nil, 0, lBufferSize);
GetMem(lAddJobInfo, lBufferSize);
try
if not AddJobW(Printer, 1, lAddJobInfo, lBufferSize, lBufferSize) then
RaiseLastOSError;
Result := lAddJobInfo.JobId;
// Copy the file into place
CopyFile(PWideChar(FileName), lAddJobInfo.Path, True);
finally
FreeMem(lAddJobInfo, lBufferSize);
end;
end;
procedure JobStart(Printer: THandle; JobID: Cardinal);
begin
if not ScheduleJob(Printer, JobID) then
RaiseLastOSError;
end;
// General cleanup
procedure ReleaseHandle(Handle: THandle);
begin
if not GlobalUnlock(Handle) then
;//RaiseLastOSError;
if GlobalFree(Handle) <> 0 then
;//RaiseLastOSError;
end;
var
PrinterA{, PrinterB}: THandle;
Defaults: PPrinterDefaultsW;
DefaultsHandle: THandle;
DataType: string;
Settings: PDeviceModeW;
SettingsHandle: THandle;
Info2: PPrinterInfo2W;
Info2Handle: THandle;
// DC: HDC;
JobID: Cardinal;
begin
if not FileExists(FileNameXPS) then
raise Exception.Create('File not found: ' + FileNameXPS);
// Get DataType
Printer_Open(PrinterA);
try
Info2_Obtain(PrinterA, Info2Handle, Info2);
try
DataType := WideCharToString(Info2.pDatatype);
finally
ReleaseHandle(Info2Handle);
end;
finally
Printer_Close(PrinterA);
end;
Defaults_Obtain(DefaultsHandle, Defaults);
try
Defaults.pDatatype := PWideChar(DataType);
Defaults.pDevMode := nil;
Defaults.DesiredAccess := PRINTER_ALL_ACCESS;
Printer_Open(PrinterA, Defaults);
try
Info2_Obtain(PrinterA, Info2Handle, Info2);
try
Settings_Show(PrinterA, Info2.pDevMode, DM_IN_BUFFER or DM_IN_PROMPT or DM_OUT_BUFFER);
// Try according to:
// - Remarks section in http://msdn.microsoft.com/en-us/library/windows/desktop/dd145082%28v=vs.85%29.aspx
// - Comment on code line 246 in http://www.lessanvaezi.com/changing-printer-settings-using-the-windows-api/
Info2.pSecurityDescriptor := nil;
Info2_Apply(PrinterA, Info2);
JobID := JobCreate(PrinterA, FileNameXPS);
JobStart(PrinterA, JobID);
finally
ReleaseHandle(Info2Handle);
end;
finally
Printer_Close(PrinterA);
end;
finally
ReleaseHandle(DefaultsHandle);
end;
end;