【问题标题】:WM_MOUSEMOVE LParam low-order OverflowWM_MOUSEMOVE LParam 低位溢出
【发布时间】:2013-12-12 09:20:37
【问题描述】:

当我在 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 中没有这样的功能。

那该怎么办呢?

【问题讨论】:

    标签: .net vb.net winforms windows-ce compact-framework2.0


    【解决方案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
    

    【讨论】:

    • 这比我的方法更优雅。非常感谢!
    猜你喜欢
    • 2016-01-22
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 2012-02-21
    • 1970-01-01
    相关资源
    最近更新 更多