You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MouseHook中MSLLHOOKSTRUCT.mouseData处理MouseWheel时值始终相同的问题

鼠标钩子无法区分滚轮前后方向问题

我已在网上竭力搜索并尝试了所有能找到的解决方案,但仍未找到可行办法。我使用鼠标钩子已有很长时间,除了无法区分鼠标滚轮向前/向后的消息外,其他功能均正常。我见过MSLLHOOKSTRUCT结构的mouseData成员被声明为Integer和UInteger,但无论采用哪种声明方式,我都无法获取WM_MOUSEWHEEL消息的HIWORD来区分滚轮方向,因为向前和向后滚动时该值始终相同。

测试输出

滚轮向前:

mouseData: 23074474
HIWORD: 352

滚轮向后:

mouseData: 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

补充说明

以下并非原问题的延续或补充问题,而是对Remy Lebeau提供的解决方案的补充说明。

供有需要的用户参考,MOUSEHOOKSTRUCTEX的定义如下:

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

非常感谢大家的帮助!

内容的提问来源于stack exchange,提问作者John89

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 05:14:57