【问题标题】:VB.NET - Making this application return two integers to set up mouse hookVB.NET - 让这个应用程序返回两个整数来设置鼠标钩子
【发布时间】:2013-11-19 11:20:12
【问题描述】:

我已经设法让this C# code不是我自己的!)在 VB.NET 中工作,以在控制台应用程序中实现鼠标挂钩。这是 VB.NET 代码:

Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Module Module1
Class InterceptMouse
    Private Shared _proc As LowLevelMouseProc = AddressOf HookCallback
    Private Shared _hookID As IntPtr = IntPtr.Zero

    Public Shared Sub Main()
        _hookID = SetHook(_proc)
        Application.Run()
        UnhookWindowsHookEx(_hookID)
    End Sub

    Private Shared Function SetHook(proc As LowLevelMouseProc) As IntPtr
        Using curProcess As Process = Process.GetCurrentProcess()
            Using curModule As ProcessModule = curProcess.MainModule
                Return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0)
            End Using
        End Using
    End Function

    Private Delegate Function LowLevelMouseProc(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr

    Private Shared Function HookCallback(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
        Dim MouseSetting As Integer = MouseMessages.WM_LBUTTONDOWN
        Dim hookStruct As MSLLHOOKSTRUCT
        If nCode >= 0 AndAlso MouseSetting = CType(wParam, MouseMessages) Then
            hookStruct = CType(Marshal.PtrToStructure(lParam, GetType(MSLLHOOKSTRUCT)), MSLLHOOKSTRUCT)
            Console.WriteLine(hookStruct.pt.x & ", " & hookStruct.pt.y)
        End If
        Dim pt As New POINT
        pt.x = hookStruct.pt.x
        pt.y = hookStruct.pt.y
        MouseCoordinates.Add(pt)
        Return CallNextHookEx(_hookID, nCode, wParam, lParam)

    End Function

    Private Const WH_MOUSE_LL As Integer = 14

    Private Enum MouseMessages
        WM_LBUTTONDOWN = &H201
        WM_LBUTTONUP = &H202
        WM_MOUSEMOVE = &H200
        WM_MOUSEWHEEL = &H20A
        WM_RBUTTONDOWN = &H204
        WM_RBUTTONUP = &H205
    End Enum

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure POINT
        Public x As Integer
        Public y As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure MSLLHOOKSTRUCT
        Public pt As POINT
        Public mouseData As UInteger
        Public flags As UInteger
        Public time As UInteger
        Public dwExtraInfo As IntPtr
    End Structure

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function SetWindowsHookEx(idHook As Integer, lpfn As LowLevelMouseProc, hMod As IntPtr, dwThreadId As UInteger) As IntPtr
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function UnhookWindowsHookEx(hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function CallNextHookEx(hhk As IntPtr, nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
    End Function

    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Private Shared Function GetModuleHandle(lpModuleName As String) As IntPtr
    End Function
End Class

然后我从 Sub Main 调用它:

Sub Main()
    InterceptMouse.Main()
End Sub

但是,当我调试它时,它转到 Application.Run() 行并且它没有前进到下一行,所以我看不到它在幕后做了什么。然后它等待用户输入并在控制台上返回整数坐标。这不是我想要它做的。我想让这段代码在另一个函数或后台工作人员中运行,每当它收到鼠标点击时将坐标传递给主线程,以便它可以处理其余部分。问题是,这段代码对于我的理解水平来说太复杂了,我真的不知道它是如何工作的。如果我至少可以设法让控制台在用户单击时返回鼠标坐标,我应该能够忽略它并从那里处理其余代码。

【问题讨论】:

  • 您是否有充分的理由使用控制台,因为您可以使用内置的 winforms 之类的东西?
  • 有充分的理由吗?哎呀,不。我想为我的计算项目制作一个控制台用户界面设计器,如果我能成功实现鼠标挂钩,那会容易得多。
  • Application.Run 不是你自己的类,对吧?它是 System.Windows.Forms 应用程序类,对吧?在这种情况下,您调用一个等待 Windows GUI 输入的 Windows 消息循环。将“Application.Run”替换为您的代码(例如“Console.ReadLine”)在鼠标钩子中设置断点并重试。

标签: c# vb.net dll mouse-hook


【解决方案1】:

有充分的理由吗?见鬼。

我喜欢你将谨慎抛诸脑后的方式。 后果自负!

不确定您将如何在控制台应用程序中使用它...

...我稍微重构了一下:

Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Module Module1

    Private counter As Integer = 0
    Private WithEvents IM As InterceptMouse

    Sub Main()
        IM = InterceptMouse.Instance
        IM.Start()

        While counter < 3
            System.Threading.Thread.Sleep(100)
        End While

        IM.Shutdown()

        Console.Write("Press Enter to Quit")
        Console.ReadLine()
    End Sub

    Private Sub IM_MouseClick(pt As InterceptMouse.POINT) Handles IM.MouseClick
        Console.WriteLine(pt.x.ToString() & ", " & pt.y.ToString())
        counter = counter + 1
    End Sub

    Public Class InterceptMouse
        Inherits ApplicationContext

        Public Event MouseClick(ByVal pt As InterceptMouse.POINT)

        Private Shared _IM As InterceptMouse
        Public Shared ReadOnly Property Instance() As InterceptMouse
            Get
                If IsNothing(_IM) Then
                    _IM = New InterceptMouse()
                End If
                Return _IM
            End Get
        End Property

        Private _proc As LowLevelMouseProc = AddressOf HookCallback
        Private _hookID As IntPtr = IntPtr.Zero
        Private T As System.Threading.Thread = Nothing

        Private Sub New()
        End Sub

        Public Sub Start()
            If IsNothing(T) Then
                T = New Threading.Thread(AddressOf Main)
                T.Start()
            End If
        End Sub

        Private Sub Main()
            _hookID = SetHook(_proc)
            Application.Run(Me)
            UnhookWindowsHookEx(_hookID)
            T = Nothing
        End Sub

        Public Sub Shutdown()
            If Not IsNothing(T) Then
                Application.Exit()
            End If
        End Sub

        Private Function SetHook(proc As LowLevelMouseProc) As IntPtr
            Using curProcess As Process = Process.GetCurrentProcess()
                Using curModule As ProcessModule = curProcess.MainModule
                    Return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0)
                End Using
            End Using
        End Function

        Private Delegate Function LowLevelMouseProc(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr

        Private Function HookCallback(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
            Dim MouseSetting As Integer = MouseMessages.WM_LBUTTONDOWN
            Dim hookStruct As MSLLHOOKSTRUCT
            If nCode >= 0 AndAlso MouseSetting = CType(wParam, MouseMessages) Then
                hookStruct = CType(Marshal.PtrToStructure(lParam, GetType(MSLLHOOKSTRUCT)), MSLLHOOKSTRUCT)
                Dim pt As New POINT
                pt.x = hookStruct.pt.x
                pt.y = hookStruct.pt.y
                RaiseEvent MouseClick(pt)
            End If
            Return CallNextHookEx(_hookID, nCode, wParam, lParam)
        End Function

        Private Const WH_MOUSE_LL As Integer = 14

        Private Enum MouseMessages
            WM_LBUTTONDOWN = &H201
            WM_LBUTTONUP = &H202
            WM_MOUSEMOVE = &H200
            WM_MOUSEWHEEL = &H20A
            WM_RBUTTONDOWN = &H204
            WM_RBUTTONUP = &H205
        End Enum

        <StructLayout(LayoutKind.Sequential)> _
        Public Structure POINT
            Public x As Integer
            Public y As Integer
        End Structure

        <StructLayout(LayoutKind.Sequential)> _
        Private Structure MSLLHOOKSTRUCT
            Public pt As POINT
            Public mouseData As UInteger
            Public flags As UInteger
            Public time As UInteger
            Public dwExtraInfo As IntPtr
        End Structure

        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function SetWindowsHookEx(idHook As Integer, lpfn As LowLevelMouseProc, hMod As IntPtr, dwThreadId As UInteger) As IntPtr
        End Function

        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function UnhookWindowsHookEx(hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

        <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function CallNextHookEx(hhk As IntPtr, nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
        End Function

        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function GetModuleHandle(lpModuleName As String) As IntPtr
        End Function

    End Class

End Module

【讨论】:

  • 太棒了。我还没有完全探索它,但它在控制台应用程序中完全可以使用:)。如果有任何问题,介意我PM你吗?
  • 问吧...我会尽可能提供帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
相关资源
最近更新 更多