2012-02-29 69 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