全局鼠标事件处理程序

全局鼠标事件处理程序

本文介绍了全局鼠标事件处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码,我从某个地方获得来捕获鼠标事件.我修改了它并制作了一个事件处理程序,以便我可以订阅它.鼠标事件被正确捕获.但它永远不会触发事件处理程序.有人能弄清楚代码有什么问题吗?

I have the following code which I got from somewhere to capture mouse events. I modified it and made an event handler so that I can subscribe to it. The mouse events are captured correctly. But it never fires the event-handler. Can anybody figure out whats wrong with the code?

public static class MouseHook
{
    public static event EventHandler MouseAction = delegate { };

    public static void Start() => _hookID = SetHook(_proc);
    public static void stop() => UnhookWindowsHookEx(_hookID);

    private static LowLevelMouseProc _proc = HookCallback;
    private static IntPtr _hookID = IntPtr.Zero;

    private static IntPtr SetHook(LowLevelMouseProc proc)
    {
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_MOUSE_LL, proc,
              GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
        {
           MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
           MouseAction(null,new EventArgs());
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

    private const int WH_MOUSE_LL = 14;

    private enum MouseMessages
    {
        WM_LBUTTONDOWN = 0x0201,
        WM_LBUTTONUP   = 0x0202,
        WM_MOUSEMOVE   = 0x0200,
        WM_MOUSEWHEEL  = 0x020A,
        WM_RBUTTONDOWN = 0x0204,
        WM_RBUTTONUP   = 0x0205
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        public int x;
        public int y;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MSLLHOOKSTRUCT
    {
        public POINT pt;
        public uint mouseData, flags, time;
        public IntPtr dwExtraInfo;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook,
      LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
      IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
}

我是这样订阅的.

MouseHook.Start();
MouseHook.MouseAction += new EventHandler(Event);

接收事件的函数.

private void Event(object sender, EventArgs e) => Console.WriteLine("Left mouse click!");

更新:我将工作代码放在一个 用于用户操作挂钩的开源 nuget 包中.

Update:I put together the working code in to a open source nuget package for user action hooks.

推荐答案

return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0);

当您在 Windows 8 之前的 Windows 版本上的 .NET 4 上运行此代码时,该代码将失败.CLR 不再模拟托管程序集的非托管模块句柄.您无法在代码中检测到此故障,因为它缺少所需的错误检查.在 GetModuleHandle 和 SetWindowsHookEx 上.pinvoke 时不要跳过错误检查,winapi 不会抛出异常.检查它们是否返回 IntPtr.Zero 并在返回时简单地抛出 Win32Exception.

This code will fail when you run it on .NET 4 on a Windows version earlier than Windows 8. The CLR no longer simulates unmanaged module handles for managed assemblies. You can't detect this failure in your code because it is missing the required error checking. Both on GetModuleHandle and SetWindowsHookEx. Never skip error checking when you pinvoke, the winapi doesn't throw exceptions. Check if they return IntPtr.Zero and simply throw a Win32Exception when they do.

修复很简单,SetWindowsHookEx() 需要一个有效的模块句柄,但在设置低级鼠标钩子时实际上并没有使用它.因此,任何句柄都可以,您可以传递 user32.dll 的句柄,该句柄始终加载在 .NET 应用程序中.修复:

The fix is simple, SetWindowsHookEx() requires a valid module handle but doesn't actually use it when you set a low-level mouse hook. So any handle will do, you can pass the handle for user32.dll, always loaded in a .NET application. Fix:

IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0);
if (hook == IntPtr.Zero)
{
    throw new System.ComponentModel.Win32Exception();
}
return hook;

这篇关于全局鼠标事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!