Delphi 10 西雅图更改为 Win32 GetPath 和冗余 TPoint 和 _POINTL 记录类型

Delphi 10 Seattle changes to Win32 GetPath and redundant TPoint and _POINTL record types

我正在尝试将一些在 Delphi XE8 中工作的代码移植到 Delphi 10 Seattle。此代码调用 Winapi.Windows.

中的 GetPath 函数

新的 Win32 API 函数签名是:

function GetPath(DC: HDC; Points: PPointL; Types: PByte; nSize: Integer): Integer; stdcall;

在 XE8 中,以前函数有 "var Points,Types",通常称为 "var untyped" 参数。

修复代码以使用 Delphi 10 Seattle 意味着 "unifying" 应用程序代码中的任意类型完全使用单元本身声明的类型。然而,让我感到困惑的是,有两种类型,PPointL 和 TPoint,当我让 GetPath 函数工作时,它填充的数据被填充到一个 _POINTL 记录数组中,因此在 Winapi.Windows:

type
  _POINTL = record      { ptl }
    x: Longint;
    y: Longint;
  end;
  {$EXTERNALSYM _POINTL}
  PPointL = ^TPointL;
  TPointL = _POINTL;

然而,还有另一种类型TPoint,声明在System.Types:

 TPoint = record
    X: FixedInt;
    Y: FixedInt;
  public

在其他地方,对于 32 位和 64 位 Windows,FixedInt 是 Longint 的别名,因此据我所知,TPoint 和 _POINTL 至少在 Windows 平台上是等效的.

如果现有应用程序组件代码都使用名为 TPoint 的类型,如下所示:

procedure AddPoint(const P:TPoint);

...我对 Delphi 10 中 RTL 源内部的实际情况有何意义?我应该采取什么方法来解决这个问题?在单位级别将 TPoint 别名为 _POINTL?

我该如何解决这个问题并继续?由于这段代码是一个商业组件,我想我会等到供应商修复它,但是,我认为理解 RTL 中的 _POINTL 和 TPoint,以及为什么这些结构在定义中是 redundantly/duplicated,会帮助其他人将低级 Win32 代码从 Delphi XE8 移植到 Delphi 10 Seattle.

更新:作为解决方法,我发现我可以重新声明函数 GetPath 的导入,并在我自己的私有单元实现区域导入中将其保持为 var untyped,然后继续:

{$ifdef D23}
{$POINTERMATH ON}
      // Delphi 10 Seattle: function GetPath(DC: HDC; Points: PPointL; Types: PByte; nSize: Integer): Integer; stdcall;
      // previously had "var Points,Types" untyped,
const
   gdi32     = 'gdi32.dll';

{$EXTERNALSYM GetPath}
function GetPath(DC: HDC; var Points, Types; nSize: Integer): Integer; stdcall; external gdi32 name 'GetPath';
{$endif}

除了在 DX Seattle 中对 Winapi.Windows.GetPath 的更改是错误的这一事实之外,对此没什么好说的。我的意思是,从技术上讲它会起作用,但它会将任何使用 GetPath 的代码留在孤立的筒仓中。

这个 TPointL 类型不是新类型,但它是 GetPath 的错误类型。 Win32 API 函数是:

int GetPath(
  _In_  HDC     hdc,
  _Out_ LPPOINT lpPoints,
  _Out_ LPBYTE  lpTypes,
  _In_  int     nSize
);

LPPOINTPOINT*POINT映射到TPoint。有一些 Win32 API 函数使用 POINTL, but the majority use POINT。当然,Microsoft 在一个就足够的情况下声明了两个相同的类型并没有帮助。

很难看出 Embarcadero 开发人员是如何在新的 GetPath 中想出 POINTL 的,但就这样吧。在我看来,你应该提交一份 QP 报告,并要求将声明从 PPointL 更改为 PPoint

同时,一个简单的转换就足够了,因为这两种类型是二进制兼容的。您希望传递 PPoint,但编译器想要 PPointL。所以传递 PPointL(...) 其中 ... 是产生 PPoint.

的表达式