2010-04-16 8 views
23

Abbiamo alcuni ganci per tastiera globali installati tramite SetWindowsHookEx con WH_KEYBOARD_LL che sembrano essere sganciati casualmente da Windows.In che modo Windows può sganciare un gancio della tastiera di livello basso (globale)?

Abbiamo verificato che il gancio non fosse più collegato perché chiamare UnhookWindowsHookEx sul manico restituisce false. (Verificato anche che restituisce true quando funzionava correttamente)

Non sembra esserci una riproduzione coerente, ho sentito che possono essere sganciati a causa di timeout o eccezioni generate, ma ho provato sia solo lasciandolo sedere su un punto di interruzione nel metodo di gestione per più di un minuto, sia semplicemente lanciando un'eccezione casuale (C#) e sembra ancora funzionare.

Nel nostro callback pubblichiamo rapidamente su un'altra discussione, quindi probabilmente non è questo il problema. Ho letto delle soluzioni in Windows 7 per impostare il timeout più alto nel registro perché Windows 7 è apparentemente più aggressivo sui timeout (stiamo tutti eseguendo Win7 qui, quindi non sono sicuro che ciò avvenga su altri sistemi operativi), ma ciò non funziona sembra una soluzione ideale

Ho considerato di avere un thread in background in esecuzione per aggiornare l'hook di tanto in tanto, che è un hacker, ma non conosco alcuna reale conseguenza negativa di farlo, e sembra meglio che modificare un impostazioni globali del registro di Windows.

Altri suggerimenti o soluzioni? Sia la classe che imposta i hook che i delegati a cui sono collegati sono statici, quindi non dovrebbero ricevere il GC.

MODIFICA: verificato con le chiamate a GC.Collect(); che funzionano ancora, in modo che non vengano raccolti garbaged.

+2

Avendo il thread che ha effettuato l'uscita chiamata SetWindowsHookEx o terminare lo farà. –

+0

@Hans Questo non è per noi, ma potrebbe aiutare qualcun altro. Sono agganciati subito prima di 'Application.Run' e sganciati subito dopo. – Davy8

+0

Mi sembra di ricordare che i thread gestiti non sono 1: 1 con thread non gestiti. Forse il thread Unmanaged è terminato? – user7116

risposta

16

Penso che questo debba essere un problema di timeout.

Altri sviluppatori hanno segnalato un problema specifico di Windows 7 con hook di basso livello che vengono sganciati se superano un valore di timeout (non documentato).

Vedere this thread per altri sviluppatori che discutono lo stesso problema.È possibile che sia necessario eseguire un ciclo occupato (o una raccolta dati obsoleta lenta) piuttosto che uno stato di sospensione per provocare il comportamento di sganciamento. Un breakpoint nella funzione LowLevelKeyboardProc potrebbe anche creare problemi di timeout. (C'è anche l'osservazione che un carico pesante della CPU da parte di un'altra attività potrebbe provocare il comportamento - presumibilmente perché l'altra attività ruba i cicli della CPU dalla funzione LowLevelKeyboardProc e ne causa troppo.)

La soluzione suggerita in quella discussione è per provare a impostare il valore LowLevelHooksTimeout DWORD nel Registro di sistema su HKEY_CURRENT_USER \ Pannello di controllo \ Desktop su un valore superiore.

Ricorda che una delle glorie di C# è che anche le semplici istruzioni possono richiedere una quantità eccessiva di tempo se si verifica una garbage collection. Questo (o caricamento della CPU da altri thread) potrebbe spiegare la natura intermittente del problema.

+7

Non è necessario andare a caccia attraverso i forum MSDN per confermare questo; è abbastanza ben documentato [qui nei documenti SDK] (http://msdn.microsoft.com/en-us/library/ms644985.aspx). Concentrati sulla sezione intitolata "Osservazioni". –

3

Ci sono due cose che ho pensato che potrebbero aiutarti a capire dove si trova il problema.

  1. Per individuare la posizione del problema, eseguire un altro gancio WH_KEYBOARD_LL in contemporanea con il tuo gancio corrente e farlo fare altro che passare i dati sulla valle della catena gancio. Quando scopri che il tuo amo originale è sganciato, controlla se questo uncino "fittizio" è stato sganciato. Se anche il gancio "fittizio" è stato sganciato, puoi essere abbastanza sicuro che il problema è fuori dal tuo hook (cioè in Windows o qualcosa relativo al tuo processo nel suo complesso?) Se i ganci "fittizi" non sono stati sganciati, allora il problema è probabilmente da qualche parte nel tuo gancio.

  2. Registra le informazioni che arrivano al tuo hook tramite la richiamata ed eseguila finché il gancio non viene sganciato. Ripetere l'operazione un numero di volte ed esaminare i dati registrati per vedere se è possibile discernere un modello che porta allo sganciamento.

Proverei questi uno alla volta, nel caso in cui entrambi influenzerebbero il risultato degli altri. Se dopo di ciò non si hanno indizi su quale potrebbe essere il problema, si potrebbe provare a eseguirli insieme.

+0

In realtà abbiamo 3 hook WH_KEYBOARD_LL, ognuno dei quali termina con 'CallNextHookEx'. Quando smette di funzionare, smettono tutti di funzionare e nulla viene colpito con i punti di interruzione impostati in tutti i callback. – Davy8

+0

È anche un po 'frustrante perché non è coerente, a volte riesco a farlo sganciare dopo qualche minuto, altre volte rimane agganciato per ore, quindi è abbastanza fastidioso eseguire il debug. – Davy8

+0

@ Davy8: sei in grado di riprodurre il problema con un solo hook 'WH_KEYBOARD_LL'? –

1

Forse qualcun altro ha un hook che non chiama CallNextHookEx()?

+0

Non ci credo, perché quando entra in questo stato, 'UnhookWindowsHookEx' sull'uncinetto restituisce' false' indicando che l'hook era sparito. – Davy8

2

È un campo lungo, ma per caso hai un software antivirus in esecuzione? Potrebbe benissimo notare un gancio della tastiera e buttarlo fuori.

È più probabile che ti avvisi e rimuoverlo immediatamente, ma è una di quelle strane cose che vale la pena controllare.

1

So che è una brutta soluzione ma è possibile impostare un timer per 5 minuti ininterrottamente, quindi è possibile riagganciare gli eventi della tastiera?

Ho avuto lo stesso problema con la macchina Win7, dopo un po 'i ganci della tastiera stavano perdendo il suo riferimento, e ho dovuto impostare un timer ogni 5 minuti per collegare nuovamente gli eventi, e ora lo mantiene fresco.

1

Sto utilizzando il seguente progetto da: http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C per eseguire attività quando è stato premuto un determinato tasto.

Ho notato che dopo aver eseguito un'operazione con un tasto di scelta rapida si è interrotto l'ascolto di nuovi tasti premuti, quindi ho cambiato il KeyboardHookListener in statico e sembrava risolvere il mio problema. Non ho idea del perché questo abbia risolto il mio problema, quindi sentitevi liberi di commentare questo!

La mia classe 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's 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(); 
     } 
    } 
} 
Problemi correlati