我已经编写了Windows打印假脱机程序API的包装类,主要工作。
唯一不起作用的是应用打印机设置 。
首先我调用DocumentProperties()来成功获取并使用打印机设置进行播放。
然后我尝试使用ResetDC()应用这些设置,但没有任何反应。 该函数需要一个有效的句柄,并返回相同的有效句柄,这意味着它应该应用设置。 但是,似乎没有任何事情发生:打印输出不受打印机设置更改的影响。
我甚至试图用9级的 SetPrinter() ,也没有效果。
这个任务变得相当紧迫。 有什么build议么?
使用Delphi XE2,Windows 7 64位。
好吧,跳过所有的大OO包装。 这是一个精简的程序版本。 (请注意,您必须给它一个XPS文件。)
正在应用打印机设置更改(使用Info2_Apply()时),并且可以在MS Word中看到。 打印时,他们只是被忽略 。 这是个谜。
我已经尝试了很多东西,我没有select。 帮助将…非常感谢。
我终于用尽了select。
这是我的testing代码的最后一个版本。 它是自包含的,包含更多的function,而不是你需要的 – 这是我拼命尝试任何我能想到的结果。
如果其他人可以使打印机设置正常工作,可以请让我知道吗?
使用以下命令填充打印机名称的combobox:
uses Printers ComboBox1.Items.Assign(Printer.Printers);
打印程序(我的testing代码):
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;