2016-12-02 43 views
4

我想在VB.net中使用DWORD WINAPI GetMessagePos(void)函數。VB.net整數和短轉換,GetMessagePos()

函數返回一個DWORD(32位),它可以存儲在VB.net整型變量中。從MSDN文檔引用:

x座標位於返回值的低位;在 y座標處於高位短(兩者都代表簽署價值 ,因爲他們可以利用負值的系統上有多個 顯示器)

我怎樣才能檢索到的X和Y座標用vb.net?

我目前正在

<System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling:=True)> 
Private Shared Function GetMessagePos() As Integer 
End Function 
Sub test() 
    Dim pos As Integer = GetMessagePos() 

    Try 
     Dim x As Short = CShort(pos And &HFFFF) 
     Dim y As Short = CShort(pos >> 16) 

     MessageBox.Show(x & ", " & y) 
    Catch ex As Exception 
     MessageBox.Show(ex.Message) 
    End Try 
End Sub 

,但我不知道這是否是做正確的方式。我試圖做一些測試,如

Try 
     Dim x As Short = -1 
     Dim y As Short = 1 

     Dim i As Int32 = (y << 16) Or x 

     Dim x2 As Short = CShort(i And &HFFFF) 
     Dim y2 As Short = CShort(i >> 16) 

     MessageBox.Show(x & ", " & y) 
    Catch ex As Exception 
     MessageBox.Show(ex.Message) 
    End Try 

基本上我碼x和y座標在短期(Int16的)變量,把它們放在一起的的Int32,然後嘗試進行解碼。
但它似乎不工作,因爲它導致溢出。

如何從GetMessagePos() WINAPI解碼x-y座標的任何想法?

回答

4

當您提取這些值以確保它們在多監視器系統上正常工作時,您必須非常小心。根據您通常在GetMessagePos函數中使用的「標準」方式,在Windows SDK頭文件中定義了GET_X_LPARAMGET_Y_LPARAM宏。這些在GetMessagePos documentation中有具體提及,並且在所有文檔中都應該對返回打包座標的函數有類似的參考。還有一個警告,不要使用經典的LOWORDHIWORD宏,因爲它們將這些值視爲無符號數量,正如您在問題中提到的那樣。

所以,任務本質上是將GET_X_LPARAMGET_Y_LPARAM宏從C語言翻譯成VB.NET。它們轉換成C#是比較簡單的,因爲你可以利用unchecked關鍵字:

int GetXValue(UInt32 lParam) 
{ 
    return unchecked((short)(long)lParam); 
} 

int GetYValue(UInt32 lParam) 
{ 
    return unchecked((short)((long)lParam >> 16)); 
} 

但VB.NET沒有爲C#的unchecked關鍵字等同,所以你必須要找到一些其他的方式,以避免溢出。就我個人而言,我使用C#編寫這種互操作代碼,並將其粘貼到一個庫中,這樣我就可以執行我發現最具可讀性的內容。

如果您更願意堅持使用VB.NET,有幾種方法可以做到這一點。最簡單的概念是將該值作爲UInt32操作以避免溢出。對於低位中的x座標,您需要明確地屏蔽高位以避免溢出。對於y座標,您需要移位並遮罩。然後你就可以回來轉換爲Short

Public Function GetXValue(lParam As UInt32) As Short 
    Return CShort(lParam And &HFFFF) 
End Function 

Public Function GetYValue(lParam As UInt32) As Short 
    Return CShort((lParam >> 16) And &HFFFF) 
End Function 

另一種選擇是更聰明一點,也許聰明,但可能更有效。它涉及聲明相當於VB中的C風格聯合。NET而言僅僅是一個結構,它的領域重疊:

<StructLayout(LayoutKind.Explicit)> _ 
Public Structure CoordUnion 

    <FieldOffset(0)> Public LParam As UInt32 
    <FieldOffset(0)> Public XCoord As Short 
    <FieldOffset(2)> Public YCoord As Short 

    Public Sub New(lParam As UInt32) 
     LParam = lParam 
    End Sub 

End Structure 

然後你可以使用它像這樣:

Dim temp As CoordUnion = New CoordUnion(GetMessagePos()) 
Dim pt As Point = New Point(temp.XCoord, temp.YCoord) 
' ... 

另請注意,我已經含蓄地改變了的P/Invoke簽名GetMessagePos所以它返回一個UInt32

<System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling:=True)> 
Private Shared Function GetMessagePos() As UInt32 
End Function 

你本來可以很容易地使用在所有這些輔助/轉換本功能的IntPtr類型離子作爲UInt32類型。事實上,這就是你通常會寫它,因爲你通常得到包裝成一個lParam值作爲窗口消息(例如,覆蓋控制的WndProc方法時)的一部分,這些指針座標。

+0

我剛剛測試了這個使用在線VB.NET編譯器和它的工作。以65537作爲輸入開始,我按照預期得到(-1,1)的座標。你的測試代碼在構建'i'仍然會產生算術溢出的問題,所以我就建在我的頭上。 :-) –