代码之家  ›  专栏  ›  技术社区  ›  Davy8

什么会导致Windows解除低级(全局)键盘挂钩?

  •  24
  • Davy8  · 技术社区  · 16 年前

    SetWindowsHookEx 具有 WH_KEYBOARD_LL

    我们确认他们的钩子不再连接,因为呼叫 UnhookWindowsHookEx false . (也证实了它会回来 true 当它正常工作时)

    似乎没有一个一致的repro,我听说它们可能会由于超时或抛出异常而被取消挂钩,但我尝试了两种方法,一种是让它在处理方法中的断点上停留一分钟以上,另一种是抛出一个随机异常(C#),它似乎仍然有效。

    在我们的回调中,我们快速地发布到另一个线程,所以这可能不是问题所在。我读过关于Windows7在注册表中设置更高超时的解决方案,因为Windows7在超时方面显然更激进(我们这里都在运行Win7,所以不确定这是否发生在其他操作系统上),但这似乎不是一个理想的解决方案。

    我曾考虑过偶尔运行一个后台线程来刷新钩子,这是很有黑客味的,但我不知道这样做会带来什么真正的负面后果,而且这似乎比更改全局Windows注册表设置要好。

    还有其他建议或解决方案吗? 设置钩子的类和它们所附加到的委托都是静态的,因此它们不应该得到GC'd。

    GC.Collect(); 他们仍然在工作,所以他们没有得到垃圾收集。

    7 回复  |  直到 16 年前
        1
  •  18
  •   MZB    16 年前

    我想这一定是个超时问题。

    其他开发人员报告了一个Windows7特有的问题,即如果低级钩子超过(未记录的)超时值,则会被解除钩子。

    看到了吗 this thread

    该线程中建议的解决方案是尝试设置 低洼地 注册表中的DWORD值

    请记住,C的一个优点是,如果发生垃圾回收,即使是简单的语句也会花费大量的时间。。这(或其他线程的CPU负载)可能解释了问题的间歇性。

        2
  •  3
  •   Zach Johnson    16 年前

    我想到了两件事,也许能帮你找出问题所在。

    1. WH_KEYBOARD_LL 与当前钩子同时钩子,让它只在钩子链上传递数据。当你发现你原来的钩子是脱钩,检查,看看这个“虚拟”钩也脱钩。如果“dummy”钩子也被解除了钩子,那么可以相当确定问题出在钩子之外(即,在Windows或与整个进程相关的东西中?),如果“dummy”钩子没有解除钩子,那么问题可能出在钩子的某个地方。

    我会一次尝试一个,以防其中一个会影响其他人的结果。如果在那之后你没有线索知道问题可能是什么,你可以试着把他们联系起来。

        3
  •  2
  •   ssube    16 年前

    这是一个长期的机会,但任何机会,你有反病毒软件运行?这很可能是注意到一个键盘挂钩并将其踢出。

        4
  •  1
  •   i_am_jorf    16 年前

    也许其他人有一个钩子没有调用CallNextHookEx()?

        5
  •  1
  •   Teoman shipahi    13 年前

    我在Win7机器上也遇到了同样的问题,过了一段时间键盘钩子失去了它的引用,我不得不每5分钟设置一个计时器来再次钩住事件,现在它让它保持新鲜。

        6
  •  1
  •   Jamie    12 年前

    http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C 当按下某个键时执行任务。

    我注意到,当我用热键执行一个任务后,它就不再监听新的按键,然后我将KeyboardHookListener改为static,它似乎解决了我的问题。我不知道为什么这解决了我的问题,所以请随意评论!

     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();
            }
        }
    }
    
        7
  •  0
  •   colin lamarre    8 年前

    很晚了,但我想和你分享一些东西。 正在从收集 here

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

    所以只需在Deactivate事件中将active bool更改为false,并在Activated事件中调用HookMouse。

    编辑:我注意到游戏速度减慢了,所以决定取消挂钩时,应用程序是不活跃的使用激活和停用事件。