SetWindowsHookEx with WH_MOUSE_LL slows down the mouse for several seconds

走远了吗. 提交于 2020-05-10 06:47:06

问题


I am using the following code to get mouse messages on the current process.

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

For some reason when this code runs the mouse get slow for several seconds and then back to normal.

Any ideas?
Thanks

EDIT - hook method

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; }
}

回答1:


What does your hook procedure look like?

If your process only has one UI thread, use a Message Filter instead: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx




回答2:


I had the same problem (only it's c++ project, not c#) and resolved it by changing hook from WH_MOUSE_LL to WH_MOUSE (from low-level to normal level). For WM_LBUTTONUP and WM_RBUTTONUP messages it works ok.

The thing that amuses me is that code with WH_MOUSE_LL was doing fine at the time I wrote it (no mouse freezes etc.) It seems like some security update for Windows changed the behavior of the mouse hooks and previously fine code become a problem.




回答3:


By setting a low level hook responsiveness of the mouse now becomes dependent on your main thread being responsive and a common mistake made is to set the hook early in the start-up process.

SetHook
LongRunningStartupProcess
Mouse isn’t responsive until here

During start-up it is best to dispatch the hook onto the thread so it happens at the end of the start-up process. Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SetHook));

DispatchSetHook
LongRunningStartupProcess
SetHook(callback)
Mouse becomes responsive

This still has ongoing management issues within your application to ensure the main thread doesn’t do any long running processes as that will lock the mouse up too. This can easily be verified by setting the hook and then doing a Thread.Sleep on the main thread.




回答4:


When you receive the hook event, turn off the book, then do your work, and if really still needed, put the hook back on.

This will stop the mouse from lagging.

Only stay hooked when you really need to.




回答5:


Your hook proc is expensive; you just need to figure out why and how to fix it.

Even though though the code looks very minimal i suspect that there is some initial C# interop expense triggering the delays, perhaps due to JIT or paging.

If you change the code to do as much processing as possible off of this thread the problem should go away. as a C++ developer I even worry about the Marshal.PtrToStructure since low-level hooks are very sensitive and I can't say off the top of my head that this operation is guaranteed to be so cheap that it wouldn't impair mouse movement.

I've used low-level mouse hooks quite a bit in the past (in C++) and have never had problems unless the hook procedure itself is expensive. In C++ I try to avoid doing anything more than a PostMessage to an HWND that does the rest of the processing.




回答6:


I am sorry to follow up after such a long time but I have solved the issue by spawning a separate thread which handles the hook (I have not added everything to the code as it also translates messages but the main idea should be clear):

    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);
    }

You can terminate the thread from any other thread by calling BeginInvoke on the created _hookControl:

        _hookControl.BeginInvoke(((Action)(() => Application.ExitThread())));


来源:https://stackoverflow.com/questions/3228293/setwindowshookex-with-wh-mouse-ll-slows-down-the-mouse-for-several-seconds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!