ResetDC()什么都不做(用于Windows的打印假脱机程序API)

时间:2012-04-27 05:25:42

标签: windows delphi printing spooler printer-properties

我为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;

0 个答案:

没有答案