Pergunta

Temos alguns ganchos globais de teclado instalados via SetWindowsHookEx com WH_KEYBOARD_LL Isso parece ser desengatado aleatoriamente pelo Windows.

Verificamos que eles não estavam mais presos porque ligar UnhookWindowsHookEx na alça retorna false. (Também verificou que retorna true quando estava funcionando corretamente)

Não parece haver uma repro consistente, ouvi dizer que eles podem ser desconectados devido a tempo limite ou exceção sendo jogada, mas tentei apenas deixá -lo ficar em um ponto de interrupção no método de manuseio por mais de um minuto, bem como apenas jogar uma exceção aleatória (c#) e ainda parece funcionar.

Em nosso retorno de chamada, publicamos rapidamente em outro tópico, para que provavelmente não seja o problema. Eu li sobre soluções no Windows 7 para definir o tempo limite mais alto no registro, porque o Windows 7 é mais agressivo com os tempos limite aparentemente (estamos todos executando o Win7 aqui, então não tenho certeza se isso ocorre em outros sistemas operacionais), mas isso não Parece uma solução ideal.

Eu pensei apenas em ter um tópico de fundo em execução para atualizar o gancho de vez em quando, o que é hackish, mas não conheço nenhuma conseqüência negativa real de fazer isso, e parece melhor do que mudar uma configuração global de registro do Windows .

Alguma outra sugestão ou soluções? A classe que define os ganchos e os delegados aos quais estão anexados são estáticos, para que não deveriam estar recebendo GC.

Editar: Verificado com chamadas para GC.Collect(); que eles ainda funcionam, então não estão sendo coletados com vestuário.

Foi útil?

Solução

Eu acho que esse deve ser um problema de tempo limite.

Outros desenvolvedores relataram um problema específico do Windows7, com ganchos de baixo nível sendo soltos se exceder um valor de tempo limite (sem documentos).

Ver este tópico Para outros desenvolvedores discutindo o mesmo problema. Pode ser que você precise realizar um loop ocupado (ou uma coleta lenta de lixo) em vez de um sono para causar o comportamento solto. Um ponto de interrupção na função LowlevelKeyboardProc também pode criar problemas de tempo limite. (Há também a observação de que uma carga pesada de CPU por outra tarefa pode provocar o comportamento - presumivelmente porque a outra tarefa rouba ciclos de CPU da função LowLevelKeyboardProc e faz com que ela demore muito.)

A solução sugerida nesse tópico é tentar definir o LowlevelHookTimeout Valor DWORD no registro em HKEY_CURRENT_USER Painel de controle Desktop para um valor maior.

Lembre -se de que uma das glórias de C# é que até declarações simples podem levar uma quantidade excessiva de tempo se ocorrer uma coleta de lixo. Essa (ou carregamento da CPU por outros threads) pode explicar a natureza intermitente do problema.

Outras dicas

Há duas coisas que pensei que podem ajudá -lo a descobrir onde está o problema.

  1. Para ajudar a isolar a localização do problema, execute outro WH_KEYBOARD_LL Coloque simultaneamente com o seu gancho atual e faça com que não faça nada senão passar os dados na corrente de gancho. Quando você descobrir que seu gancho original está desengatado, verifique e veja se esse gancho "fictício" também foi desengatado. Se o gancho "manequim" também foi desengatado, você pode ter certeza de que o problema está fora do seu gancho (ou seja, no Windows ou algo relacionado ao seu processo como um todo?) Se os ganchos "manequim" não foram desengatados, então o problema provavelmente está em algum lugar dentro do seu gancho.

  2. Registre as informações que vêm ao seu gancho através do retorno de chamada e executá -las até que o gancho seja solto. Repita isso várias vezes e examine os dados registrados para ver se você pode discernir um padrão que antecedeu o solo.

Eu tentaria um deles de cada vez, apenas para o caso de afetar o resultado dos outros. Se, depois disso, você não tiver leads sobre qual poderia ser o problema, tente executá -los juntos.

É um tiro no escuro, mas por acaso você tem software antivírus em execução? Isso poderia muito bem ser perceber um gancho de teclado e expulsá -lo.

É mais provável que ele o avisasse e o remova imediatamente, mas é uma daquelas coisas estranhas que vale a pena verificar.

Talvez alguém tenha um gancho que não esteja chamando CallNexthookex ()?

Eu sei que é uma solução feia, mas você pode definir um cronômetro para todos os 5 minutos, então você pode assar novamente seus eventos de teclados?

Eu tive o mesmo problema com a Win7 Machine, depois de um tempo os ganchos do teclado estavam perdendo sua referência, e tive que configurar um cronômetro a cada 5 minutos para conectar os eventos novamente, e agora isso o mantém fresco.

Estou usando o seguinte projeto de: http://www.codeproject.com/articles/7294/processing-global-mouse-and-keyboard-wooks-in-c para executar tarefas quando uma certa chave foi pressionada.

Percebi que, depois de executar uma tarefa com uma tecla de atalho, parou de ouvir novos presságios, mudei o tecladoHookListener para estático e parecia resolver meu problema. Não tenho ideia de por que isso resolveu meu problema, então fique à vontade para comentar sobre isso!

Minha aula de tecla de atalho:

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

Muito tarde, mas pensei em compartilhar algo. Coleta de aqui Há algumas dicas como colocar o setWindowshookex em um tópico separado e que é mais um problema de agendamento.

Também notei que o Application.doevents estava usando um pouco de CPU e descobri que o 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();
    }
}

Portanto, basta alterar o bool ativo para false no evento desativado e ligue para HookMouse no evento ativado.

Hth

EDIT: Percebi que os jogos foram desacelerados com isso, então decidi soltar quando o aplicativo não está ativo usando eventos ativados e desativados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top