2016-12-02 44 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'仍然会产生算术溢出的问题,所以我就建在我的头上。 :-) –