TPoint参数在Win32中显示正确的值,但在Win64中不显示

时间:2018-12-10 08:51:14

标签: delphi delphi-10.1-berlin

enter image description here

使用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值
msgruntimevalue

2 个答案:

答案 0 :(得分:1)

您使用的条件定义是错误的:您说两种情况下Msg.lParam3997726。那只能意味着一件事:您始终总是收到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位整数)

System.Types.TSmallPoint

System.Types.TPoint

Internal Data Formats (Delphi)

因此,当您在64位应用程序中将数据类型转换为TPoint结构时,读取X值实际上会读取同时包含X和Y值的内存块,尤其是当消息是在使用TSmallPoint结构的32位应用程序中创建的。

因此,为了解决您的问题,您将必须在应用程序的32位和64版本上统一您的数据结构,以便能够在它们两者之间发送消息。