2010-04-16 13 views
23

Tenemos algunos ganchos de teclado globales instalados a través de SetWindowsHookEx con WH_KEYBOARD_LL que parecen ser descolgados aleatoriamente por Windows.¿Qué puede hacer que Windows desenganche un gancho de teclado de bajo nivel (global)?

Verificamos que engancharon ya no se adjuntó porque llamar UnhookWindowsHookEx en el mango devuelve false. (También se verificó que devuelve true cuando estaba funcionando correctamente)

Parece que no hay una reproducción coherente, he oído que se pueden desenganchar debido a tiempos de espera o excepciones que se lanzan, pero lo he intentado ambos dejaron que se sentara en un punto crítico en el método de manejo durante más de un minuto, y arrojaron una excepción aleatoria (C#) y aún parece funcionar.

En nuestra devolución de llamada, publicamos rápidamente en otro hilo, por lo que probablemente no sea el problema. He leído sobre soluciones en Windows 7 para configurar el tiempo de espera más alto en el registro porque Windows 7 es más agresivo con los tiempos de espera aparentemente (todos estamos ejecutando Win7 aquí, así que no estoy seguro si esto ocurre en otros sistemas operativos), pero eso no Parece una solución ideal.

He considerado tener un subproceso en segundo plano para actualizar el anzuelo de vez en cuando, lo que es hackish, pero no sé de ninguna consecuencia negativa real de hacer eso, y parece mejor que cambiar un configuración global del registro de Windows.

¿Alguna otra sugerencia o solución? Tanto la clase que establece los ganchos como los delegados a los que están conectados son estáticos, por lo que no deberían recibir GC'd.

EDITAR: Verificado con llamadas al GC.Collect(); que todavía funcionan, por lo que no se van a recoger con garbaged.

+2

Tener el hilo que hizo la llamada de salida SetWindowsHookEx o terminar lo hará. –

+0

@Hans Eso no es para nosotros, pero podría ayudar a alguien más. Se conectan justo antes de 'Application.Run' y se desenganchan inmediatamente después. – Davy8

+0

Parece recordar que los hilos gestionados no son 1: 1 con hilos no gestionados. Tal vez el hilo no administrado terminó? – user7116

Respuesta

16

Creo que esto tiene que ser un problema de tiempo de espera.

Otros desarrolladores han informado de un problema específico de Windows7 con anzuelos de bajo nivel que se desenganchan si superan un valor de tiempo de espera (no documentado).

Consulte this thread para que otros desarrolladores analicen el mismo problema.Puede ser que necesite realizar un bucle ocupado (o una recolección de basura lenta) en lugar de un modo de suspensión para provocar el comportamiento de desenganche. Un punto de interrupción en la función LowLevelKeyboardProc también puede crear problemas de tiempo de espera. (También existe la observación de que una carga pesada de CPU por otra tarea podría provocar el comportamiento, presumiblemente porque la otra tarea roba ciclos de CPU de la función LowLevelKeyboardProc y hace que tarden demasiado.)

La solución sugerida en ese hilo es para intentar establecer el LowLevelHooksTimeout valor DWORD en el registro en HKEY_CURRENT_USER \ Control Panel \ Desktop a un valor mayor.

Recuerde que una de las glorias de C# es que incluso las declaraciones simples pueden tomar una cantidad excesiva de tiempo si se produce una recolección de basura .. Este (o carga de la CPU por otros hilos) podrían explicar la naturaleza intermitente del problema.

+7

No tiene que buscar en los foros de MSDN para confirmar esto; Está bastante bien documentado [aquí en los documentos SDK] (http://msdn.microsoft.com/en-us/library/ms644985.aspx). Concéntrese en la sección titulada "Observaciones". –

3

Hay dos cosas que he pensado que podrían ayudarte a descubrir dónde está el problema.

  1. Para ayudar a aislar la ubicación del problema, ejecute otra WH_KEYBOARD_LL gancho simultáneamente con su gancho de corriente y tienen que hacer nada más que pasar los datos sobre la cadena de gancho. Cuando descubra que su gancho original está desenganchado, verifique si este gancho "ficticio" también fue desenganchado. Si el gancho "ficticio" también se desenganchó, puede estar bastante seguro de que el problema está fuera de su gancho (es decir, en Windows o algo relacionado con su proceso como un todo?) Si los ganchos "ficticios" no se desengancharon, entonces el problema es probable que esté en algún lugar dentro de su gancho.

  2. Registre la información que llega a su gancho a través de la devolución de llamada y ejecútela hasta que se desenganche el gancho. Repita esto varias veces y examine los datos registrados para ver si puede discernir un patrón que conduzca a la desenganche.

Probaré estos a la vez, en caso de que cualquiera afecte el resultado de los demás. Si después de eso no tiene pistas sobre cuál podría ser el problema, puede intentar ejecutarlos juntos.

+0

Actualmente tenemos 3 ganchos WH_KEYBOARD_LL, cada uno de los cuales termina con 'CallNextHookEx'. Cuando deja de funcionar, todos dejan de funcionar y nada se golpea con los puntos de interrupción establecidos en todas las devoluciones de llamada. – Davy8

+0

También es un poco frustrante porque no es consistente, a veces puedo hacer que se desenganche después de unos minutos, otras veces queda enganchado durante horas, por lo que es bastante molesto depurar. – Davy8

+0

@ Davy8: ¿Puedes reproducir el problema con un solo gancho 'WH_KEYBOARD_LL'? –

1

Tal vez alguien más tiene un gancho que no está llamando a CallNextHookEx()?

+0

No lo creo, porque cuando se pone en este estado, 'UnhookWindowsHookEx' en el gancho devuelve' false' indicando que el enlace se ha ido. – Davy8

2

Es una posibilidad remota, pero ¿por casualidad tiene el software antivirus en ejecución? Eso podría estar notando un gancho de teclado y pateándolo.

Es más probable que lo advierta y lo elimine inmediatamente, pero es una de esas cosas extrañas que merece la pena consultar.

1

Sé que es una solución fea pero puede configurar un temporizador por 5 minutos y luego puede volver a conectar los eventos de sus teclados?

Tuve el mismo problema con la máquina Win7, después de un tiempo los ganchos del teclado estaban perdiendo su referencia, y tuve que configurar un temporizador por cada 5 minutos para enlazar eventos otra vez, y ahora lo mantiene fresco.

1

Estoy utilizando el siguiente proyecto de: http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C para realizar tareas cuando se ha presionado una tecla determinada.

Me di cuenta de que después de realizar una tarea con una tecla de acceso directo dejó de escuchar nuevas pulsaciones de teclas, luego cambié el KeyboardHookListener a estático y pareció resolver mi problema. No tengo idea de por qué esto solucionó mi problema, ¡así que no dude en comentar sobre esto!

Mi clase tecla de acceso directo:

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(); 
     } 
    } 
} 
Cuestiones relacionadas