使用Delphi代码将delphi Win32代码迁移到Win64,特别是在使用事件处理程序或采用TPoint参数的函数时:在Win32中,这显示了点的x和y坐标的正确值,但在Win64中读取x和y给出了“垃圾”值或者与 Value 相同的时间传递给它 .
在我的情况下,TDM_Point(Msg.lParam)Msg.lParam确实具有值{3997726}并且在转换为TPoint变量P之后在win32位中包含{x = 30,y = 61}并且在win64中具有值{3997726}在win32中相同,但在转换为TPoint变量后,P包含{x = 3997723,y = 0})
条件定义如下:
{$IFDEF WIN32}
TDM_Point = TSmallPoint;
{$ELSE}
TDM_Point = TPoint;
{$ENDIF}
示例代码如下:
Function process
begin
If Form.Handle = Msg.hWnd Then
begin
Control := SearchControl ( Form, TDM_Point(Msg.lParam) );
//Msg is type of tagMSG
end
end
Function Form.SearchControl ( Parent : tWinControl; P : TDM_Point ) : tControl;
Var
Index : Integer;
Control : tControl;
Rect : tRect;
tmpPoint : TPoint;
Begin
//code
end
消息值由Process Message的值返回设置
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
procedure TApplication.HandleMessage;
var
Msg: TMsg;
begin
if not ProcessMessage(Msg) then Idle(Msg);
end;
值设置如下:
If Drawing Then
Begin
{$IFNDEF WIN32}
{ Map coordinates to parent of chosen control,
or to form in no control is chosen }
If EditControls.Count > 0 Then
MapWindowPoints ( Msg.hWnd,
tControl(EditControls.Objects[0]).Parent.Handle,
Msg.lParam, 1 )
Else
MapWindowPoints ( Msg.hWnd, fEditForm.Handle,
Msg.lParam, 1 );
{$ELSE}
x:=GetSystemMetrics(SM_CXFRAME);
if abs((Msg.Pt.X-fEditForm.left-x) - TDM_Point(Msg.lParam).X) > 0 then
TDM_Point(Msg.lParam).X:=Msg.Pt.X-fEditForm.left-x;
x:=GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
if abs((Msg.Pt.Y-fEditForm.top-x) - TDM_Point(Msg.lParam).Y) > 0 then
TDM_Point(Msg.lParam).Y:=Msg.Pt.Y-fEditForm.top-x;
{$ENDIF}
Start.X := TDM_Point(Msg.lParam).X;
Start.Y := TDM_Point(Msg.lParam).Y;
Last := Start;
SetSelection;
SetClipRect;
End;
请在下面找到调用堆栈 . 我们没有准备任何消息 . 当我们点击表格的标签控制时,这是由系统准备的 . 调用堆栈的前两个函数是我们的函数,我们从vcl.forms的processmessage中获取msg值
2 回答
发生这种情况的原因是因为TSmallPoint是一个重新组合,其X和Y字段被称为Smallint(16位整数),而TPoint将其X和Y字段视为FixedInt(32位整数)
System.Types.TSmallPoint
System.Types.TPoint
Internal Data Formats (Delphi)
因此,当您在64位应用程序中将数据类型转换为TPoint结构时,读取X值实际上会读取包含X和Y值的内存块,尤其是在使用TSmallPoint结构的32位应用程序中创建了messege时 .
因此,为了解决您的问题,您必须在应用程序的32位和64位版本上统一数据结构,以便能够在两者之间发送消息 .
The conditional define you use is wrong :你说
Msg.lParam
在这两种情况下都是3997726
. 这只能意味着一件事:你 always 收到TSmallPoint
和 never a TPoint .3997726
是十六进制$003D001E
,显示16位值(两个Smallint
值),显然,即使在Win64中,您收到的
TSmallPoint
为Msg.lParam
. 所以总是强制转换为TSmallPoint
,永远不会转换为TPoint
(我无法想象你在Win32中转换为TPoint
,你可能会转换为TDM_Point
) .由于
Msg.lParam
在Win64中为64位,因此无法直接将其强制转换为TDM_Point
[1](或TSmallPoint
) - 我猜这就是为什么你在Win64中将其设为TPoint
:以匹配Msg.lParam
的大小 .但是可以相互铸造不同尺寸的整体类型 . 因此,您可以使用中间强制转换为正确大小的整数类型(此处为
UInt32
,这是一个32位无符号整数),例如就像是:然后在你的代码中:
再说一次: the message you receive always seems to contain a TSmallPoint. Do not define TDM_Point differently for different platforms.
更新
您添加的屏幕截图显示消息为WM_LBUTTONDOWN,which is very well documented:
[1]正如David Heffernan所证实的那样 .