将System.Windows.Rect强制转换为System.Windows.Point

本文关键字:System Windows Point 转换 Rect | 更新日期: 2023-09-27 18:26:10

我想在c#中转换这个c++代码:

RECT rcCurrent; ::GetWindowRect ( hwndChild, &rcCurrent ); ::MapWindowPoints ( NULL, hWnd, reinterpret_cast<LPPOINT>(&rcCurrent), 2);

但我不知道如何转换:

reinterpret_cast<LPPOINT>(&rcCurrent)

如何将System.Windows.Rect强制转换为System.Windows.Point?

将System.Windows.Rect强制转换为System.Windows.Point

哇,这真是对reinterpret_cast的滥用!代码基本上是这样说的:取一个指向包含4个整数的内存段的指针,并假设它实际上是指向包含2个整数的存储段的指针。它假设左上角的点坐标首先存储在矩形内,并且这两种类型都具有兼容的内存布局和字节对齐(这是一个非常合理的假设,但不能保证)。

在C#中最安全的做法是手动将您想要的值从Rect复制到Point对象,例如

var point = new Point(rect.x, rect.y);

更新:

一个更易于维护的选项(感谢Sven!):

var point = rect.Location;
RECT rcCurrent; ::GetWindowRect ( hwndChild, &rcCurrent );
::MapWindowPoints ( NULL, hWnd, reinterpret_cast<LPPOINT>(&rcCurrent), 2);

此代码所做的是获取子窗口(hwndChild)相对于可能的父窗口(hWnd)的客户端区域的边界矩形(rcCurrent),或者确定子窗口在其父窗口内的位置。

第一行获取子对象、边界和所有对象的完整矩形,但返回屏幕坐标。

第二条线将这些点从屏幕坐标(由第一个NULL参数指示)映射到相对于hWnd的客户端区域的坐标。

Win32没有"获取父级中的位置"调用,因此这是最近的环形交叉路口。

cast在这里所做的是利用这样一个事实,即Win32 RECT具有与两个背靠背POINT完全相同的内存布局,因此调用cPoints=2的MapWindowPoints将一次性映射整个RECT。这种用法实际上在MSDN中有记录,甚至在从右到左的镜像模式中得到了特殊处理,以确保整个矩形在从左到右布局的桌面映射到从右到右应用程序时得到正确映射,反之亦然!(如果你不打算使用R-to-L镜像,以便应用程序的本地化版本可以在希伯来语或阿拉伯语上运行,你不需要担心这一点。)

--

把它翻译成C#的正确方法取决于你从哪里开始,以及你想要实现什么。如果你正在将一个应用程序从C++大规模转换为C#,并且你有父级和子级的Control派生对象,你可以只使用child。位置以获取相对于父对象的位置。

--

另一方面,如果您正在移植根据HWND编写的代码,并且即使在移植到C#时也必须保持这种方式(例如,因为它针对来自另一个进程的HWND工作,或者不知道HWND的底层框架),那么您最好的选择是定义RECT和POINT的p/Invoke版本,这里的关键是定义一个P/Invoke版本的MapWindowPoints,它将在RECT上工作。(我假设您对这里的P/Invoke有点熟悉…)通常MapWindowPoints定义为(来自pinvoke.net):

[DllImport("user32.dll", SetLastError=true)]
public static extern int MapWindowPoints(IntPtr hwndFrom, IntPtr hwndTo, ref POINT lpPoints, [MarshalAs(UnmanagedType.U4)] int cPoints);

并且您可以使用此版本来映射单个POINT(始终将cPoints作为1传递)。然后,您还可以定义一个使用RECT:的版本

[DllImport("user32.dll", SetLastError=true)]
public static extern int MapWindowPoints(IntPtr hwndFrom, IntPtr hwndTo, ref RECT lpPoints, [MarshalAs(UnmanagedType.U4)] int cPoints);

当调用后一个版本时,总是将cPoints作为2传递。调用它将与最初的C++MapWindowPoints调用完全等效。