使用WH_MOUSE_LL的SetWindowsHookEx会使鼠标速度减慢几秒钟

问题描述 投票:3回答:6

我使用以下代码在当前进程上获取鼠标消息。

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

出于某种原因,当此代码运行时,鼠标会慢几秒钟然后恢复正常。

有任何想法吗? 谢谢

编辑 - 钩子方法

private static IntPtr mouseEvent(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
    {
        MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));     
        LastLeftClick = new ClickInfo { Time = DateTime.Now, X = hookStruct.pt.x, Y = hookStruct.pt.y };
    }
    return CallNextHookEx(hookID, nCode, wParam, lParam);
}

public class ClickInfo
{
    public int X { get; set; }
    public int Y { get; set; }
    public DateTime Time { get; set; }
}
c# winapi mouseevent
6个回答
2
投票

你的钩子程序是什么样的?

如果您的进程只有一个UI线程,请使用消息过滤器:http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx


2
投票

我有同样的问题(只有它的c ++项目,而不是c#)并通过将WH_MOUSE_LL的挂钩更改为WH_MOUSE(从低级别到正常级别)来解决它。对于WM_LBUTTONUP和WM_RBUTTONUP消息,它可以正常工作。

让我感到高兴的是WH_MOUSE_LL的代码在我编写时没有用(没有鼠标冻结等)。似乎Windows的一些安全更新改变了鼠标钩子的行为,之前的精细代码成了问题。


2
投票

通过设置鼠标的低级钩子响应性现在变得依赖于主线程的响应,并且常见的错误是在启动过程中尽早设置钩子。

SetHook LongRunningStartupProcess 直到这里鼠标才响应

在启动期间,最好将挂钩分配到线程上,以便在启动过程结束时发生。 Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SetHook));

DispatchSetHook LongRunningStartupProcess SetHook(回调) 鼠标变得敏感

这仍然存在应用程序中的持续管理问题,以确保主线程不会执行任何长时间运行的进程,因为这也将锁定鼠标。这可以通过设置钩子然后在主线程上执行Thread.Sleep来轻松验证。


1
投票

当你收到钩子事件时,关掉书,然后做你的工作,如果真的还需要,把钩子重新打开。

这将阻止鼠标滞后。

只有在真正需要的时候才会保持迷茫。


1
投票

你的钩子是昂贵的;你只需要弄清楚为什么以及如何解决它。

即使代码看起来很小,但我怀疑有一些初始的C#互操作费用会触发延迟,可能是由于JIT或分页。

如果您更改代码以尽可能多地处理此线程,则问题应该消失。作为一名C ++开发人员,我甚至担心Marshal.PtrToStructure,因为低级别的钩子非常敏感,我不能说这个操作保证是如此便宜以至于不会损害鼠标移动。

我过去曾经使用过低级别的鼠标钩子(在C ++中),并且除非钩子程序本身很昂贵,否则从未出现过问题。在C ++中,我尝试避免对执行剩余处理的HWND执行除PostMessage之外的任何操作。


0
投票

很抱歉在很长一段时间后跟进,但是我通过产生一个处理钩子的单独线程解决了这个问题(我没有在代码中添加所有东西,因为它也会翻译消息,但主要想法应该是清楚的):

    public Form1()
    {
        InitializeComponent();

        Thread thread = new Thread(HookThread);
        thread.IsBackground = true;
        thread.Start();
    }

    private void HookThread()
    {
        _hookControl = new Control();
        IntPtr handle = _hookControl.Handle;

        _hookProc = new HookProc(HookFunction);
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            _hook = SetWindowsHookEx(HookType.WH_MOUSE_LL, _hookProc, GetModuleHandle(curModule.ModuleName), 0);// (uint)AppDomain.GetCurrentThreadId());
        }

        Application.Run();

        UnhookWindowsHookEx(_hook);
        _hook = IntPtr.Zero;
    }

    private IntPtr HookFunction(int code, IntPtr wParam, IntPtr lParam)
    {
        if (code < 0)
        {
            //you need to call CallNextHookEx without further processing
            //and return the value returned by CallNextHookEx
            return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
        }

        int msg = wParam.ToInt32();
        string messages = string.Join(", ", _messageMapping.Where(t => t.Item1 == msg).Select(t => t.Item2));
        if (string.IsNullOrWhiteSpace(messages))
            messages = msg.ToString();
        Trace.WriteLine($"Messages: { messages }");

        //return the value returned by CallNextHookEx
        return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
    }

您可以通过在创建的_hookControl上调用BeginInvoke来终止来自任何其他线程的线程:

        _hookControl.BeginInvoke(((Action)(() => Application.ExitThread())));
© www.soinside.com 2019 - 2024. All rights reserved.