PDevMode 和 DocumentProperties。在 Delphi 7+XE 之间迁移时出错

Posted

技术标签:

【中文标题】PDevMode 和 DocumentProperties。在 Delphi 7+XE 之间迁移时出错【英文标题】:PDevMode and DocumentProperties. Error when Migrating between Delphi 7+XE 【发布时间】:2012-07-31 18:26:53 【问题描述】:

我有以下功能,用于收集我正在打印的 PDF 的文档属性。 出于某种原因,在 Delphi 7(运行 XP)中,这很好用...但是,当我尝试使用 Windows 7 使用 Delphi XE 重新编译时,该函数似乎总是退出失败...dwRet = IDOK

我注意到我在 Delphi 7 中的 dwNeeded 对象是 7332,而在 XE 中是 4294967295!!

知道如何快速解决这个问题吗?

Function TPrintPDF.GetPrinterDevMode ( pDevice: PChar ): PDevMode;
Var
  pDevModeVar : PDevMode;
  pDevModeVar2 : PDevMode;
  dwNeeded : DWord;
  dwRet : DWord;
Begin

   Start by opening the printer 
  If (Not OpenPrinter (pDevice, PrinterHandle, Nil))
    Then Result := Nil;

   Step 1: Allocate a buffer of the correct size 
  dwNeeded := DocumentProperties (0,
                         PrinterHandle,  Handle to our printer 
                         pDevice,  Name of the printer 
                         pDevModevar^,  Asking for size, so these are not used 
                         pDevModeVar^,
                         0);  Zero returns buffer size 

  GetMem (pDevModeVar, dwNeeded);

   Step 2: Get the default DevMode for the printer 
  dwRet := DocumentProperties (0,
                 PrinterHandle,
                 pDevice,
                 pDevModeVar^,  The address of the buffer to fill 
                 pDevModeVar2^,  Not using the input buffer 
                 DM_OUT_BUFFER);  Have the output buffer filled 

   If failure, cleanup and return failure 
  If (dwRet <> IDOK) Then Begin
    FreeMem (pDevModeVar);
    ClosePrinter (PrinterHandle);
    Result := Nil;
  End;

   Finished with the printer 
  ClosePrinter (PrinterHandle);

   Return the DevMode structure 
  Result := pDevModeVar;

End;  GetPrinterDevMode Function 

【问题讨论】:

dwNeeded 应声明为LONG。它已签署。负值表示函数失败。这正是发生在你身上的事情。调用DocumentProperties 时不会检查错误。 DocumentProperties 的 Delphi 标头翻译很可能是假的。 所以我可以为 dwNeeded 使用 Int64 而不是 DWord? 不,就像我说的,它应该声明为LONG。我也想知道将垃圾传递给第 4 和第 5 参数是否明智。 不要使用Int64!使用来自WindowsLONG。或者Integer,如果你必须的话。你不妨试着准确一点。在这个例程中,您的错误处理也完全被破坏了。 这种“行得通”,投入生产,不管Delphi公司是否匹配API,90%的时候在升级开发环境或操作系统时都会停止工作.正如@David 所建议的,您可能是准确的!!! 【参考方案1】:

以下是我在您的代码中看到的问题:

    DocumentProperties 的返回值是一个带符号的 32 位整数。它被声明为LONG。负值表示发生了错误,这就是发生在您身上的事情。只有您看不到负值,因为您已将该值填充到无符号整数中。不幸的是,XE 未能声明LONG。因此,将您的代码更改为使用IntegerDocumentProperties 返回时不会检查错误。如果发生错误,则返回负值。请务必检查。 您将第四个和第五个参数中的随机垃圾传递给DocumentProperties。我怀疑您第一次调用DocumentProperties 时可以为这两个参数传递nil。您当然可以在两次调用函数时都为第 5 个参数传递 nil,因为您从未设置过 DM_IN_BUFFER。 发生错误时,您将Result 设置为nil,但您继续执行该函数的其余部分。不要那样做。调用 exit 退出函数。分配给Result 不会像return 在类C 语言中那样终止执行。 使用try/finally 块确保您调用CloseHandle。这样您就可以只写一次CloseHandle

【讨论】:

【参考方案2】:

这是大卫建议的解决方案...谢谢大卫!

 ---------------------------------------------------------------------------- 

Function TPrintPDF.GetPrinterDevMode                           (         pDevice: PChar                ): PDevMode;


Var
   pDevModeVar       : PDevMode;
   pDevModeVar2      : PDevMode;
   dwNeeded          : Long64;
   dwRet             : Long64;


Begin

  Result := Nil;

   Start by opening the printer 
  If (OpenPrinter (pDevice, PrinterHandle, Nil)) Then Begin

    Try

       Step 1: Allocate a buffer of the correct size 
      dwNeeded := DocumentProperties (0,
                                      PrinterHandle,   Handle to our printer 
                                      pDevice,         Name of the printer   
                                      Nil,             Asking for size, so these are not used 
                                      Nil,
                                      0);              Zero returns buffer size 

       Exit if this fails 
      If (dwNeeded < 0)
        Then Exit;

      GetMem (pDevModeVar, dwNeeded);


       Step 2: Get the default DevMode for the printer 
      dwRet := DocumentProperties (0,
                                   PrinterHandle,
                                   pDevice,
                                   pDevModeVar^,       The address of the buffer to fill 
                                   pDevModeVar2^,      Not using the input buffer 
                                   DM_OUT_BUFFER);     Have the output buffer filled 


       If failure, cleanup and return failure 
      If (dwRet <> IDOK) Then Begin
        FreeMem (pDevModeVar);
        ClosePrinter (PrinterHandle);
        Result := Nil;
      End;


     Finished with the printer 
    Finally
      ClosePrinter (PrinterHandle);
    End;  Try 

     Return the DevMode structure 
    Result := pDevModeVar;

  End;  If we could open the printer 


End;  GetPrinterDevMode Function 

【讨论】:

这绝对不是我建议的!我建议使用LONG 而不要传递像pDevModeVar2^ 这样的随机垃圾。我还建议正确处理错误。当您调用DocumentProperties 时,您不会检查错误。当您检查错误时,您没有正确执行。 XE 不支持 LONG 类型。所以我坚持使用 Int64。至于错误处理......你有什么建议?我对这种级别的编程相当陌生。 确实我在 windows.pas 中也找不到 LONG。使用“Longint”,这就是在“winspool.pas”中声明“DocumentProperties”的方式。或者,建议的“整数”.. @Sertac 我想我错误地启动了 XE2。它在那里声明。 @David - 确实。他们应该更频繁地更改图标.. :)

以上是关于PDevMode 和 DocumentProperties。在 Delphi 7+XE 之间迁移时出错的主要内容,如果未能解决你的问题,请参考以下文章

如何使用直接 2d 在打印机 DC 中绘制文本?

delphi如何打印到指定的打印机

& 和 && 区别和联系,| 和 || 区别和联系

第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等

shell中$()和 ` `${}${!}${#}$[] 和$(()),[ ] 和(( ))和 [[ ]]

Java基础8---面向对象代码块和继承和this和super和重写和重载和final