RECT rcCurrent; ::GetWindowRect ( hwndChild, &rcCurrent );
::MapWindowPoints ( NULL, hWnd, reinterpret_cast<LPPOINT>(&rcCurrent), 2);
这段代码所做的是获取子窗口 (hwndChild) 相对于可能的父窗口 (hWnd) 的客户区的边界矩形 (rcCurrent) - 或确定子窗口在其父窗口内的位置。
第一行获取孩子的完整矩形、边框和所有内容,但它以屏幕坐标返回。
第二行将这些点从屏幕坐标(由第一个 NULL 参数指示)映射到相对于 hWnd 客户区的坐标。
Win32 没有“在父级中获取位置”调用,因此这是最近的环形交叉路口等效项。
演员在这里所做的是利用 Win32 RECT 具有与两个背靠背 POINT 完全相同的内存布局这一事实,因此使用 cPoints=2 调用 MapWindowPoints 将一次性映射整个 RECT 。这种用法实际上记录在 MSDN中,甚至在从右到左的镜像模式中得到特殊处理,以确保在从左到右布局的桌面映射到从右到左的应用程序时,整个矩形得到正确映射,反之亦然!(如果您不打算使用 R-to-L 镜像以使您的应用程序的本地化版本可以在希伯来语或阿拉伯语上运行,则无需担心这一点。)
--
将其转换为 C# 的正确方法取决于您从哪里开始以及您想要实现的目标。如果您要将应用程序从 C++ 批量转换为 C#,并且您有父级和子级的 Control 派生对象,则可以使用child.Location获取相对于父级的位置。
--
另一方面,如果您要移植根据 HWND 编写的代码,并且即使移植到 C# 也必须保持这种状态(例如,因为它正在处理来自另一个进程的 HWND 或者不知道 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);
...并且您可以使用此版本来映射单个 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);
And when calling this latter version, always pass in cPoints as 2. Calling this would then be the exact C# equivalent of the original C++ MapWindowPoints call.