我正在尝试将一些在 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 函数工作时,它填充的数据被填充到一个 _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,因此至少在 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}