c# keyboard-hook setwindowshookex

c# - ¿Qué puede hacer que Windows desenganche un gancho de teclado(global) de bajo nivel?



keyboard-hook setwindowshookex (7)

¿Quizás alguien más tiene un enlace que no está llamando a CallNextHookEx ()?

Tenemos algunos ganchos de teclado globales instalados a través de SetWindowsHookEx con WH_KEYBOARD_LL que parece que Windows se desengancha al azar.

Verificamos que el enganche ya no estaba adjunto porque la llamada a UnhookWindowsHookEx en el identificador devuelve false . (También se verificó que devuelve true cuando funcionaba correctamente)

No parece haber una repetición consistente, he oído que pueden desconectarse debido a los tiempos de espera o a las excepciones que se lanzan, pero he intentado que ambos queden en un punto de interrupción en el método de manejo durante más de un minuto. así como simplemente lanzar una excepción aleatoria (C #) y todavía parece funcionar.

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

He considerado tener un hilo de fondo en ejecución para actualizar el gancho de vez en cuando, lo que es un error, pero no sé de ninguna consecuencia negativa real de hacerlo, y parece mejor que cambiar una configuración de registro global 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 a GC.Collect(); que todavía funcionan, por lo que no están siendo recogidos garbaged.


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

Otros desarrolladores han informado de un problema específico de Windows7 con la desconexión de los enlaces de bajo nivel si superan un valor de tiempo de espera (no documentado).

Vea este hilo para otros desarrolladores que discuten el mismo problema. Puede ser que necesite realizar un ciclo de ocupado (o una recolección de basura lenta) en lugar de un modo de espera 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 se observa que una carga pesada de la CPU por otra tarea podría provocar el comportamiento, probablemente porque la otra tarea roba los ciclos de la CPU de la función LowLevelKeyboardProc y hace que demore demasiado).

La solución sugerida en ese hilo es intentar establecer el valor DWORD de LowLevelHooksTimeout 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 de tiempo excesiva si se produce una recolección de basura. Esto (o la carga de la CPU por otros subprocesos) podría explicar la naturaleza intermitente del problema.


Es una posibilidad remota, pero por casualidad, ¿está ejecutando un software antivirus? Eso podría muy bien notar un gancho de teclado y patearlo.

Es más probable que te lo advierta y lo elimine de inmediato, pero es una de esas cosas extrañas que vale la pena revisar.


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

Noté que después de realizar una tarea con una tecla de acceso rápido, 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 resolvió mi problema, ¡así que siéntase libre de comentar sobre esto!

Mi clase de tecla de acceso rápido:

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


Hay dos cosas en las 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 otro enganche WH_KEYBOARD_LL simultáneamente con su enganche actual y haga que haga nada más que pasar los datos en la cadena del enganche. Cuando descubra que su gancho original está desenganchado, verifique si este gancho "ficticio" también fue desenganchado. Si el gancho "ficticio" también fue desconectado, 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 fueron desenganchados, entonces el problema es probablemente en algún lugar dentro de su gancho.

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

Intentaría esto de uno en uno, por si acaso alguno de los dos afectaría 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.


Muy tarde pero pensé en compartir algo. Recopilando desde here hay un par de sugerencias, como colocar a SetWindowsHookEx en un hilo separado y que es más un problema de programación.

También noté que Application.DoEvents estaba usando bastante CPU, y descubrí que PeekMessage usa menos.

public static bool active = true; [StructLayout(LayoutKind.Sequential)] public struct NativeMessage { public IntPtr handle; public uint msg; public IntPtr wParam; public IntPtr lParam; public uint time; public System.Drawing.Point p; } [SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool PeekMessage(out NativeMessage message, IntPtr handle, uint filterMin, uint filterMax, uint flags); public const int PM_NOREMOVE = 0; public const int PM_REMOVE = 0x0001; protected void MouseHooker() { NativeMessage msg; using (Process curProcess = Process.GetCurrentProcess()) { using (ProcessModule curModule = curProcess.MainModule) { // Install the low level mouse hook that will put events into _mouseEvents _hookproc = MouseHookCallback; _hookId = User32.SetWindowsHookEx(WH.WH_MOUSE_LL, _hookproc, Kernel32.GetModuleHandle(curModule.ModuleName), 0); } } while (active) { while (PeekMessage(out msg, IntPtr.Zero, (uint)WM.WM_MOUSEFIRST, (uint)WM.WM_MOUSELAST, PM_NOREMOVE)) ; Thread.Sleep(10); } User32.UnhookWindowsHookEx(_hookId); _hookId = IntPtr.Zero; } public void HookMouse() { active = true; if (_hookId == IntPtr.Zero) { _mouseHookThread = new Thread(MouseHooker); _mouseHookThread.IsBackground = true; _mouseHookThread.Priority = ThreadPriority.Highest; _mouseHookThread.Start(); } }

así que simplemente cambie el bool activo a falso en el evento Desactivar y llame a HookMouse en el evento Activado.

HTH

EDITAR: noté que los juegos se ralentizaron con esto, así que decidí desconectar cuando la aplicación no está activa usando los eventos Activado y Desactivar.


Sé que es una solución fea, pero puedes configurar un temporizador cada 5 minutos y luego puedes volver a conectar los eventos de tu teclado.

Tuve el mismo problema con la máquina Win7, después de un tiempo los ganchos del teclado perdían su referencia, y tuve que configurar un temporizador por cada 5 minutos para volver a conectar los eventos, y ahora lo mantiene actualizado.