0

当我在 WndProc 中收到WM_MOUSEMOVE消息时,lParam 包含光标坐标。我将此参数转换为Point结构:

Friend Shared Function LParamToPoint(ByVal lParam As IntPtr) As Point
    Return New Point(LOWORD(lParam.ToInt32()), HIWORD(lParam.ToInt32()))
End Function

Friend Shared Function HIWORD(ByVal value As Integer) As Short
    Return CShort((value >> 16))
End Function

Friend Shared Function LOWORD(ByVal value As Integer) As Short
    Return CShort((value And UShort.MaxValue))
End Function

我的问题是,当光标的 x 坐标变为负数时,LOWORD 函数会因溢出异常而失败。根据 MSDN,您应该使用GET_X_LPARAMGET_Y_LPARAM宏,而不是 HI/LO WORD 宏。但是在 vb.net 中没有这样的功能。

那么该怎么办?

4

1 回答 1

1

溢出检查确实妨碍了这里。解决这个问题的最好方法是声明一个union。联合是具有重叠值的结构。它优雅地允许您将 IntPtr 覆盖在具有 Short 类型的结构成员之上。转换速度极快,不会抛出溢出异常。

将一个新模块添加到您的项目中,将其命名为 NativeMethods 并使其如下所示:

Imports System.Runtime.InteropServices
Imports System.Drawing

Module NativeMethods
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure LParamMap
        Public Sub New(value As IntPtr)
            lparam = value
        End Sub

        Public Shared Widening Operator CType(value As LParamMap) As Point
            Return New Point(value.loword, value.hiword)
        End Operator

        <FieldOffset(0)> Public lparam As IntPtr
        <FieldOffset(0)> Public loword As Short
        <FieldOffset(2)> Public hiword As Short
    End Structure

End Module

我为 Point 添加了一个转换运算符,因为那是您真正想要的。一些执行此操作的测试代码:

Imports System.Drawing
Imports System.Diagnostics

Module Module1
    Sub Main()
        Debug.Assert(BitConverter.IsLittleEndian)
        Dim test As New LParamMap(New IntPtr(-1))
        Debug.Assert(test.loword = -1)
        Debug.Assert(test.hiword = -1)
        Dim pos As Point = test
        Debug.Assert(pos = New Point(-1, -1))
    End Sub
 End Module

它现在变成了一个非常简单的单行代码,例如覆盖表单的 WndProc() 方法:

Protected Overrides Sub WndProc(ByRef m As Windows.Forms.Message)
    If m.Msg = &H200 Then
        Dim pos As Point = New LParamMap(m.LParam)
        '' etc...
    End If
    MyBase.WndProc(m)
End Sub
于 2013-12-12T14:41:16.617 回答