Подтвердить что ты не робот

Что может привести к тому, что Windows отцепит низкоуровневую (глобальную) клавиатуру?

У нас есть несколько глобальных клавиатурных крючков, установленных через SetWindowsHookEx с WH_KEYBOARD_LL, которые кажутся случайным образом отцеплены Windows.

Мы проверили, что они больше не привязаны, потому что вызов UnhookWindowsHookEx в дескрипторе возвращает false. (Также проверено, что он возвращает true, когда он работает правильно)

Кажется, что нет последовательного воспроизведения, я слышал, что они могут отцепляться из-за тайм-аутов или исключений, которые могут быть сброшены, но я попробовал как просто позволить ему сидеть на контрольной точке в методе обработки для более минута, а также просто бросать случайное исключение (С#), и оно все еще работает.

В нашем обратном вызове мы быстро отправляем сообщение в другой поток, так что, вероятно, это не проблема. Я прочитал о решениях в Windows 7 для установки тайм-аута выше в реестре, потому что Windows 7 более агрессивно относится к таймаутам (мы все запускаем Win7 здесь, поэтому не уверен, что это происходит на других ОС), но это не так 'похоже на идеальное решение.

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

Любые другие предложения или решения? Оба класса, который устанавливает крючки и связанные с ними делегаты, являются статическими, поэтому они не должны получать GC'd.

EDIT: проверено с помощью вызовов GC.Collect();, что они все еще работают, поэтому они не собираются собирать мусор.

4b9b3361

Ответ 1

Я думаю, что это должна быть проблема с тайм-аутом.

Другие разработчики сообщили о специфической проблеме Windows7 с отцеплением низкого уровня, если они превышают значение (недокументированное) тайм-аута.

Смотрите этот поток для других разработчиков, обсуждающих ту же проблему. Возможно, вам нужно выполнить цикл занятости (или медленную сборку мусора), а не спящий режим, чтобы вызвать отцепление. Точка останова в функции LowLevelKeyboardProc также может создавать проблемы с тайм-аутом. (Также наблюдалось, что большая загрузка процессора другой задачей может спровоцировать поведение - по-видимому, потому, что другая задача крадет циклы процессора из функции LowLevelKeyboardProc и заставляет ее занять слишком много времени.)

Решение, предложенное в этом потоке, заключается в попытке установить значение LowLevelHooksTimeout DWORD в реестре на HKEY_CURRENT_USER\Control Panel\Desktop на большее значение.

Помните, что одна из славы С# заключается в том, что даже простые операторы могут занимать чрезмерное количество времени, если происходит сборка мусора. Это (или загрузка процессора другими потоками) может объяснить прерывистый характер проблемы.

Ответ 2

Есть две вещи, о которых я подумал, которые могут помочь вам выяснить, в чем проблема.

  • Чтобы помочь изолировать местоположение проблемы, запустите еще один крюк WH_KEYBOARD_LL одновременно с вашим текущим крюком и не делайте ничего, кроме передачи данных по цепочке крюков. Когда вы узнаете, что ваш оригинальный крючок отцеплен, проверьте и проверьте, не был ли этот крюк "dummy" снят. Если крюк "dummy" также был отцеплен, вы можете быть достаточно уверены, что проблема находится за пределами вашего крючка (то есть в Windows или что-то, связанное с вашим процессом в целом?) Если крючки "dummy" не были отцеплены, тогда проблема вероятно, где-то внутри вашего крюка.

  • Зарегистрируйте информацию, которая попадает на ваш крючок через обратный вызов, и запускайте его до тех пор, пока крюк не будет отцеплен. Повторите это несколько раз и просмотрите зарегистрированные данные, чтобы увидеть, можете ли вы различить шаблон, ведущий к отцеплению.

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

Ответ 3

Это длинный выстрел, но случайно у вас есть антивирусное программное обеспечение? Это очень хорошо заметило крючок клавиатуры и выгнал его.

Скорее всего, это предупредит вас и немедленно удалит его, но это одна из тех странных вещей, которые стоит проверить.

Ответ 4

Возможно, у кого-то есть крючок, который не вызывает CallNextHookEx()?

Ответ 5

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

У меня была такая же проблема с машиной Win7, после того, как клавиатурные крючки теряли ее ссылку, и мне приходилось настраивать таймер каждые 5 минут, чтобы снова перехватывать события, и теперь он сохраняет его свежими.

Ответ 6

Я использую следующий проект: http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C для выполнения задач при нажатии определенного ключа.

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

Мой класс hotkey:

 class Hotkey
{
    private static KeyboardHookListener _keyboardHookListener;

    public void Start()
    {
        _keyboardHookListener = new KeyboardHookListener(new GlobalHooker()) { Enabled = true };
        _keyboardHookListener.KeyDown += KeyboardListener_OnkeyPress;
    }

    private void KeyboardListener_OnkeyPress(object sender, KeyEventArgs e)
    {
        // Let backup all projects
        if (e.KeyCode == Keys.F1)
        {
            // Initialize files
            var files = new Files();

            // Backup all projects
            files.BackupAllProjects();
        }
        // Quick backup - one project
        else if (e.KeyCode == Keys.F2)
        {
            var quickBackupForm = new QuickBackup();
            quickBackupForm.Show();
        }
    }
}