Che cosa può causare Windows per sganciare un basso livello di hook di tastiera (globale)?

StackOverflow https://stackoverflow.com/questions/2655278

Domanda

Abbiamo alcuni ganci tastiera globali installati tramite SetWindowsHookEx con WH_KEYBOARD_LL che sembrano casualmente ottenere sganciato da Windows.

Abbiamo verificato che il gancio non era più attaccato perché chiamando UnhookWindowsHookEx sui rendimenti maniglia false. (Inoltre verificato che restituisce true quando funzionava correttamente)

Ci non sembra essere un Repro coerente, ho sentito che si può ottenere sganciato a causa di timeout o eccezioni farsi espellere, ma ho provato sia solo lasciando riposare su un punto di interruzione nel metodo di gestione per oltre un minuto, così come appena gettare un'eccezione casuale (C #) e sembra ancora al lavoro.

Nel nostro callback abbiamo inviare rapidamente a un altro thread, in modo che probabilmente non è il problema. Ho letto su soluzioni in Windows 7 per l'impostazione del timeout più elevato nel Registro di sistema perché Windows 7 è più aggressivo sui timeout apparentemente (siamo tutti in esecuzione Win7 qui, quindi non so se questo si verifica su altri OS), ma che doesn 't sembrare una soluzione ideale.

Ho considerato solo avere un thread in background in esecuzione per aggiornare il gancio di tanto in tanto, che è hackish, ma non so di eventuali conseguenze negative reali di farlo, e sembra meglio che cambiare a livello globale impostazione del registro di Windows.

Altri suggerimenti o soluzioni? La classe che imposta i ganci ei delegati che stanno attaccati alla sono statici, in modo che non dovrebbe essere sempre GC'd.

EDIT:. Verificata con chiamate a GC.Collect(); che ancora il lavoro, in modo che non stanno ottenendo garbaged raccolti

È stato utile?

Soluzione

Credo che questo deve essere un problema di timeout.

Altri sviluppatori hanno segnalato un problema specifico Windows7 con ganci basso livello sganciato se superano un (non documentato) valore di timeout.

questa discussione per gli altri sviluppatori parlano dello stesso problema. Può essere che è necessario eseguire un ciclo occupato (o un lento Garbage Collection), piuttosto che un sonno a causare il comportamento sgancio. Un punto di interruzione nella funzione LowLevelKeyboardProc potrebbe anche creare problemi di timeout. (C'è anche l'osservazione che un carico della CPU pesante da un altro compito potrebbe provocare il comportamento -. Presumibilmente perché l'altro compito ruba cicli di CPU dalla funzione LowLevelKeyboardProc e lo fa prendere troppo tempo)

La soluzione suggerita in quel filo è quello di provare a impostare il LowLevelHooksTimeout Valore DWORD nel Registro di sistema a HKEY_CURRENT_USER \ Control Panel \ Desktop per un valore maggiore.

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

Altri suggerimenti

Ci sono due cose che ho pensato che potrebbe aiuto a capire dove sia il problema.

  1. per aiutare a isolare 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 si scopre che il vostro gancio originale è sganciato, controllare e vedere se questo gancio "fittizio" è stato anche sganciato. Se il gancio "fittizio" è stata anche sganciato, si può essere abbastanza certi che il problema è al di fuori del vostro gancio (ad esempio in Windows o qualcosa legato al vostro processo nel suo insieme?) Se i ganci "fittizi" non è stato sganciato, allora il problema è probabilmente da qualche parte all'interno del vostro gancio.

  2. Registro le informazioni che arrivano al vostro gancio tramite il callback e correre fino a quando il gancio viene sganciato. Ripetere questa operazione un numero di volte ed esaminare i dati registrati per vedere se è possibile scorgere un modello che porta al sganciamento.

vorrei provare questi uno alla volta, nel caso in cui entrambi i inciderebbe esito degli altri. Se dopo che non hai conduce su quale sia il problema potrebbe essere, si potrebbe provare a correre insieme.

E 'un campo lungo, ma per caso non si dispone di software anti-virus in esecuzione? Che potrebbero benissimo essere notando un gancio tastiera e calci fuori.

E 'più probabile che sarebbe in guardia, e rimuoverlo immediatamente, ma è una di quelle cose strane pena di verificare.

Forse qualcun altro ha un gancio che non sta chiamando CallNextHookEx ()?

Lo so che è una soluzione brutta, ma è possibile impostare un timer per sempre cinque minuti, allora è possibile ri-agganciare i tuoi tastiere eventi?

ho avuto un lo stesso problema con la macchina Win7, dopo un po 'ganci tastiera stavano perdendo esso di riferimento, e ho dovuto impostare un timer per ogni 5 minuti per agganciare di nuovo gli eventi, e ora lo mantiene fresco.

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

Ho notato che dopo che ho eseguito un compito con un tasto di scelta rapida si è fermato ad ascoltare per i nuovi tasti premuti, quindi ho cambiato il KeyboardHookListener per statica e sembrava per risolvere il mio problema. Non ho idea del perché questo risolto il mio problema, quindi sentitevi liberi di commentare su 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();
        }
    }
}

Molto in ritardo, ma ho pensato di condividere qualcosa. La raccolta da qui c'è un paio di suggerimenti come mettere il SetWindowsHookEx in un thread separato e che è più un problema di programmazione.

Ho anche notato che Application.DoEvents stava usando un po 'di CPU, e ha scoperto che PeekMessage utilizza meno.

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

quindi basta cambiare il bool attiva su false nella all'evento Disattivazione e chiamare HookMouse in caso attivato.

HTH

EDIT: ho notato i giochi sono stati rallentati con questo, così ha deciso di sganciare quando app non è attiva utilizzando Attivato ed eventi Disattiva

.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top