我正在尝试将一些在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的别名,所以就我所知,TPoint和_POINTL至少在Windows平台上是等效的。
如果现有的应用程序组件代码全部使用名为TPoint的类型,如下所示:
procedure AddPoint(const P:TPoint);
......我对Delphi 10中RTL源内部的情况有何意义?我应该怎样解决这个问题?别名TPoint到单位级_POINTL?
如何解决此问题并继续?由于此代码是商业组件,我想我会等到供应商修复此问题,但是,我认为理解RTL中的_POINTL和TPoint,以及为什么这些结构在定义中冗余/重复,将有助于其他人将低级Win32代码从Delphi XE8移植到Delphi 10 Seattle。
更新:作为一种解决方法,我发现我可以重新声明GetPath函数的导入,并在我自己的私有单元实现区域导入中将其保留为var无类型,并继续:
{$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}
答案 0 :(得分:9)
除了DX西雅图的Winapi.Windows.GetPath
更改错误之外,没有什么可说的。我的意思是,从技术上讲它会起作用,但它会留下任何在孤立的孤岛中使用GetPath
的代码。
此TPointL
类型不是新类型,但它是GetPath
的错误类型。 Win32 API函数是:
int GetPath(
_In_ HDC hdc,
_Out_ LPPOINT lpPoints,
_Out_ LPBYTE lpTypes,
_In_ int nSize
);
LPPOINT
POINT*
和POINT
映射到TPoint
。有些Win32 API函数使用POINTL
,但大多数使用POINT
。当然,当一个人满足时,微软并没有提供两种相同类型的帮助。
很难看出Embarcadero开发者如何在新POINTL
中设法GetPath
,但你去了。在我看来,您应该提交QP报告并请求声明从PPointL
更改为PPoint
。
与此同时,简单的强制转换就足够了,因为这两种类型是二进制兼容的。您希望传递PPoint
,但编译器需要PPointL
。通过PPointL(...)
,其中...
是产生PPoint
的表达式。