我想在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?
答案 0 :(得分:4)
reinterpret_cast
的滥用!代码基本上是说:取一个指向包含4个整数的内存部分的指针,并假装它实际上是指向包含2个整数的内存部分的指针。它假设左上角坐标首先存储在矩形内,并且两种类型都具有兼容的内存布局和字节对齐(这是一个非常合理的假设,但不能保证)。
在C#中最安全的做法是手动将所需的值从Rect
复制到Point
对象,例如
var point = new Point(rect.x, rect.y);
<强>更新强>
更易于维护的选择(谢谢Sven!):
var point = rect.Location;
答案 1 :(得分:2)
RECT rcCurrent; ::GetWindowRect ( hwndChild, &rcCurrent );
::MapWindowPoints ( NULL, hWnd, reinterpret_cast<LPPOINT>(&rcCurrent), 2);
此代码正在做的是获取子窗口(hwndChild)的边界矩形(rcCurrent)相对于可能父窗口(hWnd)的客户区域 - 或确定子窗口在其父窗口内的位置。
第一行获取子项的完整矩形,边框和全部,但它会以屏幕坐标返回。
第二行将这些点从屏幕坐标(由第一个NULL参数指示)映射到相对于hWnd的客户区域的坐标。
Win32没有“在父级内获取位置”调用,因此这是最近的环形交叉口等价物。
演员在这里做的是利用Win32 RECT具有与两个背对背POINT相同的精确相同的内存布局这一事实,因此调用MapPindowPoints与cPoints = 2将映射整个RECT一气呵成。这个用法实际上是documented in MSDN,甚至在从右到左镜像模式中得到特殊处理,以确保从左到右布局桌面映射到从右到左映射时整个矩形都能正确映射应用程序,反之亦然! (如果您不打算使用R-to-L镜像,以便您的应用程序的本地化版本可以使用希伯来语或阿拉伯语运行,则无需担心这一点。)
-
将此转换为C#的正确方法取决于您从哪里开始以及您要实现的目标。如果您正在将应用程序批发从C ++转换为C#,并且您拥有父项和子项的Control派生对象,则可以使用child.Location获取相对于父项的位置。
-
另一方面,如果您正在移植使用HWND编写的代码,并且即使在移植到C#时也必须保持这种方式(例如,因为它正在对来自另一个进程的HWND起作用或者不知道底层框架)对于HWNDs,那么你最好的选择是定义RECT和POINT的P / Invoke版本,这里的关键是定义一个可以在RECT上运行的P / Invoke版本的MapWindowPoints。 (我假设你在这里稍微熟悉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调用的C#等价物。