后台线程中的 LowLevelMouseProc

发布于 2024-09-25 12:46:31 字数 747 浏览 1 评论 0原文

我正在尝试在后台线程上设置鼠标挂钩。

delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
LowLevelMouseProc _proc = HookCallback;
SetWindowsHookEx(PInvoke.WH_MOUSE_LL, _proc, IntPtr.Zero, 0);

如果

IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam){/**/}

我将其放在主窗口线程上,则一切正常,直到窗口必须执行更复杂的工作,这会导致鼠标在该工作期间停止响应(例如更新面板中的多个子项)。

如果我启动一个新线程并从那里设置挂钩,问题是线程在设置挂钩后简单地退出,并且永远不会调用回调函数。

有没有办法为此目的保持线程活动? 或者是否存在另一种连接鼠标而不冒无响应行为风险的方法?

我意外地注意到,当工作线程执行时,

GetMessage(out msg, new IntPtr(0), 0, 0);

不会收到任何消息,但线程出于所需目的而保持活动状态。 我还需要一种优雅的方式来关闭线程,但 GetMessage 永远不会返回。

我不太明白所有这些消息,我只是希望能够连接鼠标并防止其冻结。

任何帮助都是appriced。

I'm trying to setup mouse hook on background thread.

delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
LowLevelMouseProc _proc = HookCallback;
SetWindowsHookEx(PInvoke.WH_MOUSE_LL, _proc, IntPtr.Zero, 0);

and

IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam){/**/}

If I put this on the main window thread everything works until window has to do more complicated work which causes mouse to stop responding for the duration of that work (updating multiple children in panel for example).

If I start a new Thread and from there set up the hook, the problem is the thread simply exits after setting up the hook and callback function is never called.

Is there a way to keep thread alive for this purpose?
Or if another way exists for hooking up mouse without risking unresponsive behavior?

I accidentaly noticed that when worker thread executes

GetMessage(out msg, new IntPtr(0), 0, 0);

No message is ever recieved but thread is being kept alive for the required purpose.
Also I need an elegant way to close the thread, but GetMessage never returns.

I don't quite understand all these messages, I simply want to be able to hook up mouse and secure it against freezing.

Any help is appriciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美人迟暮 2024-10-02 12:46:32

低级鼠标钩子需要在名为 SetWindowsHookEx 的线程中运行消息循环。这就是为什么它不能在简单的后台线程中工作,而可以在 UI 线程中工作。如果要在后台线程中使用此钩子,请在 SetWindowsHookEx 之后调用 Application.Run 方法。线程保留在此循环中并处理低级挂钩消息。

Low level mouse hook requires message loop running in the thread which called SetWindowsHookEx. This is why it doesn't work in a simple background thread, and works in UI thread. If you want to use this hook in background thread, call Application.Run method after SetWindowsHookEx. Thread remains in this loop and handles low level hook messages.

孤者何惧 2024-10-02 12:46:32

我的程序中也有类似的问题。
创建键盘钩子后,钩子回调被传递给 UI 线程。当 UI 线程繁忙时,回调位于 UI 调度程序队列中,但如果回调持续时间太长,Windows 将取消挂钩。
我尝试为此回调创建单独的线程是没有用的,直到我尝试在该线程中运行单独的调度程序。
所以,我试图用这段代码解决我的问题:

private void InitializeKeyboardHookWithSeparateDispatcher()
    {
        using (var objCreated = new ManualResetEventSlim(false))
        {
            var thread = new Thread(() =>
            {
                _keyboardListener = new KeyboardListener();
                // ReSharper disable once AccessToDisposedClosure
                objCreated.Set();
                System.Windows.Threading.Dispatcher.Run();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
            objCreated.Wait();
        }
    }

KeyboardListener 是我的高级抽象,它实际上在内部调用 SetWindowsHookEx。
我使用 Manualreseteventslim 因为 KeyboardListener 需要通过构造函数注入注入到我的程序的其他对象中。

I had similar problem in my program.
After creation of keyboard hook callback of hook were passed to UI thread. When UI thread was busy callback was in UI dispatcher queue, but windows will unhook you if callback will last for too long.
My tries with creating of separate thread for this callbacks were useless until I tried to run separate Dispatcher in that thread.
So, I'm trying to solve my problem with this code:

private void InitializeKeyboardHookWithSeparateDispatcher()
    {
        using (var objCreated = new ManualResetEventSlim(false))
        {
            var thread = new Thread(() =>
            {
                _keyboardListener = new KeyboardListener();
                // ReSharper disable once AccessToDisposedClosure
                objCreated.Set();
                System.Windows.Threading.Dispatcher.Run();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
            objCreated.Wait();
        }
    }

KeyboardListener is my high level abstraction which actually calls SetWindowsHookEx inside.
I'm using manualreseteventslim because KeyboardListener need to be injected in other objects of my program with constructor injection.

折戟 2024-10-02 12:46:32

在您的钩子回调方法中,只需启动一个新线程即可。像这样的事情:

IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    ThreadPool.QueueUserWorkItem(obj =>
    {
        // do whatever ...
    });
}

如果您的处理需要访问控件上的表单,请不要忘记在主线程上调用。

编辑:

如果您在主窗体线程上执行某些操作会冻结 UI,则应考虑在后台线程而不是主线程中执行该操作。当您需要因处理而更新控件时,您可以调用。

this.WhateverControl.Invoke( /* ... /* );

In your hook callback method simply launch a new thread. Something like this:

IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    ThreadPool.QueueUserWorkItem(obj =>
    {
        // do whatever ...
    });
}

Don't forget to invoke on your main thread if your processing requires access to your forms on controls.

EDIT:

If you're doing something on your main form thread that is freezing up the UI, you should consider doing that action in a background thread instead of the main thread. When you need to update the controls as a result of your processing, then you can invoke.

this.WhateverControl.Invoke( /* ... /* );

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文