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
!使用来自Windows
的LONG
。或者Integer
,如果你必须的话。你不妨试着准确一点。在这个例程中,您的错误处理也完全被破坏了。
这种“行得通”,投入生产,不管Delphi公司是否匹配API,90%的时候在升级开发环境或操作系统时都会停止工作.正如@David 所建议的,您可能是准确的!!!
【参考方案1】:
以下是我在您的代码中看到的问题:
DocumentProperties
的返回值是一个带符号的 32 位整数。它被声明为LONG
。负值表示发生了错误,这就是发生在您身上的事情。只有您看不到负值,因为您已将该值填充到无符号整数中。不幸的是,XE 未能声明LONG
。因此,将您的代码更改为使用Integer
。
DocumentProperties
返回时不会检查错误。如果发生错误,则返回负值。请务必检查。
您将第四个和第五个参数中的随机垃圾传递给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 之间迁移时出错的主要内容,如果未能解决你的问题,请参考以下文章
第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等