我写的包装类Windows的后台打印程序的API ,其工作...居多。
不工作的唯一的事情是将打印机设置 。
首先,我叫DocumentProperties()成功收购,并与打印机设置播放。
然后我尝试应用使用这些设置ResetDC(),但没有任何反应。 该功能需要一个有效的句柄,并返回相同的有效处理,这意味着它应该应用的设置。 但是,似乎没有任何已经发生:打印输出是由打印机设置的改变的影响。
我甚至试着使用SetPrinter()与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;