开发者

LowLevelMouseProc in background thread

开发者 https://www.devze.com 2023-01-18 07:12 出处:网络
I\'m tr开发者_Go百科ying to setup mouse hook on background thread. delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

I'm tr开发者_Go百科ying 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.


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.


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.


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( /* ... /* );

0

精彩评论

暂无评论...
验证码 换一张
取 消