2012-02-29 71 views
1

我想在C#转换这个C++代码:演员System.Windows.Rect到System.Windows.Point

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

但我不知道如何改变:

reinterpret_cast<LPPOINT>(&rcCurrent)

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

+0

你想如何改变它们?一个描述了一个矩形,另一个描述了一个点。实际上,矩形应该描述什么?如果没有这些信息,就不可能说出你可能想如何映射它们。 – Chris 2012-02-29 09:23:49

回答

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

这段代码做的是得到的边框(rcCurrent)子窗口(hwndChild)相对于大概父窗口(hWnd)的客户区 - 或者确定子窗口在其父窗口内的位置。

第一行获取子项,边框和全部的完整矩形,但它会返回到屏幕坐标中。

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

Win32没有“获取父母内的位置”调用,所以这是最接近的回旋等效。

什么演员阵容在这里做,走的是一个事实,即一个Win32 RECT有确切相同的内存布局两回至后端的积分优势,因此调用与cPoints MapWindowPoints = 2将映射在整个RECT一个去。这个用法实际上是documented in MSDN,甚至在从右到左镜像模式中得到特殊处理以确保当从左到右布局桌面映射到从右到左应用程序时整个矩形被正确映射,并且恶意-versa! (如果你不打算使用R-到-L镜像,因此您的应用是本地化版本可以在希伯来文或阿拉伯文运行,你不需要担心这个。)

-

将此转换为C#的正确方法取决于您从哪里开始,以及您想要实现的目标。如果您将应用程序批量从C++转换为C#,并且您有父级和子级的Control派生对象,则可以使用child.Location来获取相对于父级的位置。

-

在另一方面,如果你正在移植上所写的HWNDs方面,具有代码保持,即使移植到C#(如,那是因为它的工作对HWNDs从另一个进程或不知道HWND的底层框架),那么最好的办法是定义RECT和POINT的P/Invoke版本,这里的关键是定义一个可以在RECT上工作的MapWindowPoints的P/Invoke版本。 (我假设你有点熟悉的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); 

...你可以使用此版本地图的单点(总是将c点传递为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#相当于原来的C++ MapWindowPoints通话。

3

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

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

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

UPDATE:

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

var point = rect.Location; 
+1

我只想补充说'Rect'结构有一个属性可以为你做这个,所以你可以说'Point p = rect.Location;'。它不仅比原来的'reinterpret_cast'更安全(不依赖于内存布局),而且它更加语义化,更易读,因此更易于维护。 – Sven 2012-02-29 09:37:38

+0

谢谢Sven,这很完美 – Gat 2012-02-29 10:15:18

+0

说明reinterpret_cast的用法:MapWindowPoints的第二个参数是要翻译的点数;所以这里发生的事情是,代码使用一个强制转换来处理一个RECT - 它是4个整数 - {top,left,bottom,right};就好像它的*两个* POINTs - {top,left}和{bottom,right}。这是因为两者如何定义。这是一种古老的Win32成语,虽然这可能不是一般的C语言使用,但由于Win32 API *要求* POINT/RECT具有这些特定的二进制布局,所以*可以保证在Win32上工作* *。但它仍然很难看:) – BrendanMcK 2012-02-29 11:50:51