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



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

我注意到我在Delphi7中的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 }

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

  1. DocumentProperties的返回值是一个有符号的32位整数。它被声明为LONG。负值意味着发生了错误,这就是发生在你身上的情况。只是你看不到负值,因为你把这个值塞进了一个无符号整数。遗憾的是XE未能声明LONG。因此,请将代码更改为使用Integer
  2. DocumentProperties返回时,您不检查错误。如果发生错误,则返回负值。一定要检查一下
  3. 您正在将第4个和第5个参数中的随机垃圾传递给DocumentProperties。我怀疑您在第一次调用DocumentProperties时可以为这两个参数传递nil。您当然可以在两次调用函数时都为第5个参数传递nil,因为您从未设置DM_IN_BUFFER
  4. 当出现错误时,可以将Result设置为nil,但可以继续执行函数的其余部分。不要那样做。调用exit以中断函数。分配给Result不会像return在类C语言中那样终止执行
  5. 使用try/finally块确保调用CloseHandle。这允许您只写一次CloseHandle

以下是David建议的解决方案。。。谢谢大卫!

{ ---------------------------------------------------------------------------- }
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 }

最新更新