使用Delphi代码将delphi Win32代码迁移到Win64,尤其是在使用事件处理程序或带有TPoint参数的函数时:在Win32中,这显示了该点的x和y坐标的正确值,但是在Win64中,读取x和y给出了“垃圾” '值或与值传递时间相同的时间。
在我的情况下为TDM_Point(Msg.lParam) Msg.lParam确实具有值{3997726},并且在转换为TPoint之后在win32位和win64中变量P包含{x = 30,y = 61}在Win32中,Msg.lParam确实具有值{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
消息值由过程消息返回的值设置
[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的进程消息中获取msg值
答案 0 :(得分:1)
您使用的条件定义是错误的:您说两种情况下Msg.lParam
是3997726
。那只能意味着一件事:您始终总是收到TSmallPoint
,而永远不会收到TPoint
。
3997726
是十六进制$003D001E
,它显示16位值(两个Smallint
值),
X = $001E (decimal value 30)
Y = $003D (decimal value 61).
很明显,即使在 Win64 中,您也会收到TSmallPoint
的{{1}}。因此,始终强制转换为Msg.lParam
,永远不要强制转换为TSmallPoint
(我无法想象您在 Win32 中强制转换为TPoint
,您很可能强制转换为{{1 }}。
由于TPoint
是 Win64 中的64位,因此您不能直接将其投射到TDM_Point
[1] (或{{ 1}})—我想这就是为什么您在 Win64 中将其设置为Msg.lParam
:以匹配TDM_Point
的大小。
但是大小不同的 integral 类型可以相互转换。因此,您可以将中间类型转换为大小正确的整数类型(此处为TSmallPoint
,这是一个32位无符号整数),例如像这样:
TPoint
以及随后的代码中:
Msg.lParam
再次重申:您收到的消息似乎总是包含TSmallPoint。请勿为不同的平台分别定义TDM_Point。
您添加的屏幕截图显示该消息为WM_LBUTTONDOWN,which is very well documented:
lParam
低位字指定光标的x坐标。坐标相对于客户区域的左上角。
高阶单词指定光标的y坐标。坐标相对于客户区域的左上角。
[1] 正如David Heffernan确认的。
答案 1 :(得分:-1)
发生这种情况的原因是因为TSmallPoint被记录为X和Y字段为Smallint(16位整数),而TPoint将其X和Y字段为FixedInt(32位整数)
Internal Data Formats (Delphi)
因此,当您在64位应用程序中将数据类型转换为TPoint结构时,读取X值实际上会读取同时包含X和Y值的内存块,尤其是当消息是在使用TSmallPoint结构的32位应用程序中创建的。
因此,为了解决您的问题,您将必须在应用程序的32位和64版本上统一您的数据结构,以便能够在它们两者之间发送消息。