Delphi 10 Seattle对Win32 GetPath的更改以及冗余的TPoint和_POINTL记录类型

8

我希望您能帮助将一些在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一起使用意味着将应用程序代码中的任意类型“统一”为使用在单元本身中声明的确切类型。然而,让我感到困惑的是,有两种类型,PPointL和TPoint,当我让GetPath函数工作时,它所填充的数据填充到一个_WINAPI.WINDOWS中声明的_POINTL记录数组中。
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

在其他平台上,FixedInt被别名为Longint,无论是32位还是64位的Windows系统,因此,在至少Windows平台上,TPoint和_POINTL是等价的。

如果现有的应用程序组件代码都使用名为TPoint的类型,像这样:

procedure AddPoint(const P:TPoint);

我该如何理解Delphi 10中RTL源代码中的情况?我该如何修复它?应该在单元级别将TPoint重命名为_POINTL吗?
我该如何修复并继续进行?由于此代码是商业组件,我想等待供应商修复此问题,但是了解RTL中的_POINTL和TPoint以及为什么这些结构在定义中会出现重复将有助于其他人将低级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}

这些类型并不是多余的,因为它们似乎都在某个地方被使用了,但我同意使用了错误的类型。应该使用 PPoint 而不是 PPointL - Rudy Velthuis
@RudyVelthuis 一些 Win32 API 使用 POINTL 而不是 POINT,原因我无法理解。但是是的,GetPath 使用 POINT - David Heffernan
@DavidHeffernan:这就是我说在Delphi中POINTL类型不是多余的原因。顺便说一下,POINTLRECTL似乎被用于Metafile APIs中。我不知道为什么它们不能使用普通的POINTRECT结构体。可能是微软内部有竞争的开发组,彼此之间没有沟通。<g> - Rudy Velthuis
1个回答

9

关于这个问题,除了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,但大多数使用 POINT。当然,微软声明了两种完全相同的类型,这并没有起到帮助作用。
很难看出 Embarcadero 开发人员如何在新的 GetPath 中采用了 POINTL,但是事实就是这样。在我看来,您应该提交一个 QP 报告,并要求将声明从 PPointL 更改为 PPoint
与此同时,简单地进行类型转换即可,因为这两种类型是二进制兼容的。您想传递一个 PPoint ,但编译器需要 PPointL。所以,请传递 PPointL(...),其中 ... 是生成 PPoint 的表达式。

这个问题在Delphi 10.1 Berlin中已经得到解决。 https://quality.embarcadero.com/browse/RSP-12086 - Warren P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接