代码之家  ›  专栏  ›  技术社区  ›  John89

MouseHook-MSLLHOOKSTRUCT.mouseData在处理MouseWheel时总是返回相同的值

  •  0
  • John89  · 技术社区  · 1 年前

    我不知疲倦地在网上搜索,并尝试了我遇到的所有可能的解决方案;但无法找到有效的解决方案。

    我有一个鼠标挂钩,我已经用了很长时间了,除了当我试图区分向前/向后的鼠标滚轮消息时,它的效果很好。

    我看过 mouseData 的成员 MSLLHOOKSTRUCT 结构声明为 Integer UInteger 。不管怎样申报,我都无法获得 HIWORD 对于 WM_MOUSEWHEEL 消息来区分向前和向后,因为当我向前或向后滚动时,值总是相同的。

    测试输出 :

    车轮向前:

    鼠标数据:23074474
    HIWORD:352

    车轮后部:

    鼠标数据:23074474
    HIWORD:352

    密码 :

        <Extension>
        Public Function HIWORD(value As Integer) As Integer
            Return BitConverter.ToInt16(BitConverter.GetBytes(value), 2)
        End Function
    
        Private Shared MouseHookProcedure As HookProcHandler
        Private Shared PreviousCallback As Object()
        Private Shared ProcPtrSet As Boolean
        Private Shared HookHandle As IntPtr
    
        Public Shared Function Start() As Boolean
            If HookHandle <> IntPtr.Zero Then Return True
            If Not ProcPtrSet Then
                ProcPtrSet = True
                MouseHookProcedure = New HookProcHandler(AddressOf HookProc)
            End If
            Using p As Process = Process.GetCurrentProcess()
                Using m As ProcessModule = p.MainModule
                    SetWindowsHookEx(HOOKTYPE.WH_MOUSE, MouseHookProcedure, Pinvoke.Kernel32.Functions.GetModuleHandle(m.ModuleName), Pinvoke.Kernel32.Functions.GetCurrentThreadId)
                End Using
            End Using
            If HookHandle = 0 Then Return False Else Return True
        End Function
    
        Public Shared Function [Stop]() As Boolean
            Return UnhookWindowsHookEx(HookHandle)
        End Function
    
        Private Shared Function HookProc(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As Integer
            Dim MSLLHS As MSLLHOOKSTRUCT = Marshal.PtrToStructure(lParam, GetType(MSLLHOOKSTRUCT))
            If nCode < 0 Then
                Return CallNextHookEx(HookHandle, nCode, wParam, lParam)
            Else
                ' Catch duplicate messages caused by the default behavior of the MouseProc function.
                Dim Msg As MouseMessages = CType(wParam, MouseMessages)
                If PreviousCallback IsNot Nothing Then
                    If CType(PreviousCallback(0), MouseMessages) = Msg AndAlso CompairMSLLHOOKSRUCT(PreviousCallback(1), MSLLHS) AndAlso CType(PreviousCallback(2), Date) = Now Then
                        GoTo NextCallback
                    End If
                End If
                ' Raise Event
                Select Case Msg
                    Case MouseMessages.MouseWheel
                        Msg = If(CType(MSLLHS.mouseData, Integer).HIWORD > 0, MouseMessages.MouseWheelForward, MouseMessages.MouseWheelBack)
                        RaiseEvent Message(Msg MSLLHS)
                    Case Else
                        RaiseEvent Message(Msg, MSLLHS)
                End Select
                PreviousCallback = New Object(2) {CType(wParam, MouseMessages), MSLLHS, Now}
    NextCallback:
                Try
                    Return CallNextHookEx(HookHandle, nCode, wParam, lParam)
                Catch ex As Exception
                    Return [Stop]()
                End Try
            End If
        End Function
    
        Private Shared Function CompairMSLLHOOKSRUCT(left As MSLLHOOKSTRUCT, right As MSLLHOOKSTRUCT) As Boolean
            Return left.pt.X = right.pt.X AndAlso left.pt.Y = right.pt.Y AndAlso left.mouseData = right.mouseData AndAlso left.flags = right.flags AndAlso left.time = right.time AndAlso left.dwExtraInfo = right.dwExtraInfo
        End Function
    

    Pinvoke :

    Public Delegate Function HookProcHandler(nCode As System.Int32, wParam As System.IntPtr, lParam As System.IntPtr) As System.Int32
    
    <DllImport(User32, CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)>
    Public Shared Function UnhookWindowsHookEx(idHook As System.IntPtr) As System.Boolean
    End Function
    
    <DllImport(User32, CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)>
    Public Shared Function SetWindowsHookEx(idHook As System.Int32, lpfn As HookProcHandler, hInstance As System.IntPtr, threadId As System.Int32) As System.IntPtr
    End Function
    
    <DllImport(User32, CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)>
    Public Shared Function CallNextHookEx(hhk As System.IntPtr, nCode As System.Int32, wParam As System.IntPtr, lParam As System.IntPtr) As System.IntPtr
    End Function
    
    <DllImport(Kernel32, CharSet:=CharSet.Auto, SetLastError:=True)>
    Public Shared Function GetModuleHandle(lpModuleName As System.String) As System.IntPtr
    End Function
    
    <StructLayout(LayoutKind.Sequential)>
    Public Structure MSLLHOOKSTRUCT    
        Public pt As POINT
        Public mouseData As System.UInt32
        Public flags As System.UInt32
        Public time As System.UInt32
        Public dwExtraInfo As System.IntPtr
    End Structure
    
    <StructLayout(LayoutKind.Sequential)>
    Public Structure POINT
        Public X As System.Int32
        Public Y As System.Int32
        Public Sub New(ByVal X As System.Int32, ByVal Y As System.Int32)
            Me.X = X
            Me.Y = Y
        End Sub
    End Structure
    
    Public Enum MouseMessages As System.UInt32
        MouseWheel = WindowsMessages.WM_MOUSEWHEEL ' &H20E
        ' Etc...
    End Enum
    

    编辑
    这不是原问题的延续,也不是附加问题,而是对 solution 由提供 Remy Lebeau .

    对于任何可能需要它的人, MOUSEHOOKSTRUCTEX 定义如下:

    <StructLayout(LayoutKind.Sequential)>
    Public Structure MOUSEHOOKSTRUCTEX    
        Public mouseHookStruct As MOUSEHOOKSTRUCT       
        Public mouseData As System.Int32    
    End Structure
    

    非常感谢你们的帮助!

    1 回复  |  直到 1 年前
        1
  •  3
  •   Remy Lebeau    1 年前

    你的 HookProc 使用了错误的结构类型。

    您正在安装 WH_MOUSE 钩子,它使用 MOUSEHOOKSTRUCT 其中的结构 lParam 。但是您的代码正在铸造 l参数 MSLLHOOKSTRUCT 结构,由使用 WH_MOUSE_LL WH_MOUSE (因此 LL 在结构的名称中)。

    因此 MSLLHOOKSTRUCT.mouseData 您试图在内存中访问的字段实际上是 MOUSEHOOKSTRUCT.hwnd 领域该值保持不变,因为连续 WM_MOUSEWHEEL 消息很可能被发送到同一个窗口。

    请注意,没有 mouseData 中的字段 mousehook结构 结构。然而,有一个 鼠标数据 中的字段 MOUSEHOOKSTRUCTEX 结构。所以你可以投 l参数 当消息为 WM_滚轮 .

    还要注意,根据实施方式, WM_滚轮 可能是合成消息,而不是实际的鼠标事件,因此它可能根本不会显示在任何鼠标挂钩中。您可能需要考虑使用 WH_GETMESSAGE WH_CALLWNDPROC 钩子而不是 WH_MOUSE