LowLevelMouseProc в фоновом потоке - PullRequest
       10

LowLevelMouseProc в фоновом потоке

2 голосов
/ 03 октября 2010

Я пытаюсь настроить мышиный крючок в фоновом потоке.

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 никогда не возвращается.

Я не совсем понимаю все эти сообщения, я просто хочу иметь возможность подключить мышь и обезопасить ее от замерзания.

Любая помощь ценится.

Ответы [ 3 ]

1 голос
/ 11 ноября 2010

Низкоуровневая перехват мыши требует цикла сообщений, запущенного в потоке, который называется SetWindowsHookEx. Вот почему он не работает в простом фоновом потоке, а работает в потоке пользовательского интерфейса. Если вы хотите использовать эту ловушку в фоновом потоке, вызовите метод Application.Run после SetWindowsHookEx. Поток остается в этом цикле и обрабатывает сообщения перехвата низкого уровня.

0 голосов
/ 07 апреля 2018

У меня была похожая проблема в моей программе.После создания клавиатурного хука обратный вызов хука был передан в поток пользовательского интерфейса.Когда поток пользовательского интерфейса был занят, обратный вызов находился в очереди диспетчера пользовательского интерфейса, но Windows отцепит вас, если обратный вызов будет длиться слишком долго.Мои попытки создания отдельного потока для этих обратных вызовов были бесполезны, пока я не попытался запустить отдельный Dispatcher в этом потоке.Итак, я пытаюсь решить мою проблему с помощью этого кода:

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 необходимо внедрить в другие объекты моей программы с помощью конструктора.

0 голосов
/ 03 октября 2010

В вашем методе обратного вызова ловушек просто запустите новый поток. Примерно так:

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

Не забудьте вызвать в главном потоке, если ваша обработка требует доступа к вашим формам в элементах управления.

EDIT:

Если вы делаете что-то в основном потоке форм, который замораживает пользовательский интерфейс, вам следует рассмотреть возможность выполнения этого действия в фоновом потоке вместо основного потока. Когда вам нужно обновить элементы управления в результате вашей обработки, вы можете вызвать.

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

...