我们通过SetWindowsHookEx
和WH_KEYBOARD_LL
安装了一些全局键盘钩子(Hook),这些钩子(Hook)似乎被Windows随机钩住了。
我们验证了它们的钩子(Hook)不再连接,因为在句柄上调用UnhookWindowsHookEx
返回false
。 (还验证了它在正常工作时返回true
)
似乎没有一致的再现,我听说它们可能由于超时或抛出异常而脱钩,但我尝试将它们放在处理方法的断点上一分钟以上,以及仅引发随机异常(C#),它似乎仍然有效。
在回调中,我们快速将其发布到另一个线程,所以这可能不是问题。我已经读过有关Windows 7中用于在注册表中设置更高超时的解决方案的信息,因为Windows 7显然在超时方面更具攻击性(我们都在这里运行Win7,因此不确定是否在其他OS上发生这种情况),但是似乎不是理想的解决方案。
我曾考虑过让后台线程每隔一段时间运行一次刷新钩子(Hook),这有点黑,但我不知道这样做有任何实际的负面影响,而且它似乎比更改全局Windows注册表设置要好。 。
还有其他建议或解决方案吗? 设置钩子(Hook)的类和它们所附加的委托(delegate)都是静态的,因此它们不应获取GC。
编辑:通过对GC.Collect();
的调用进行验证,它们仍然可以正常工作,因此不会被垃圾回收。
最佳答案
我认为这一定是超时问题。
其他开发人员报告了Windows7特定的问题,如果它们超过了(未记录的)超时值,则会解除钩住低级挂钩。
有关其他讨论相同问题的开发人员,请参见this thread。可能是因为您需要执行繁忙的循环(或缓慢的垃圾回收),而不是进行睡眠,才能导致取消钩住行为。 LowLevelKeyboardProc函数中的断点也可能会导致超时问题。 (还观察到另一个任务的CPU负载过重可能会引起该行为-大概是因为另一个任务从LowLevelKeyboardProc函数窃取了CPU周期,并导致其花费了太长时间。)
该线程中建议的解决方案是尝试将注册表中 HKEY_CURRENT_USER\Control Panel\Desktop 的注册表中的 LowLevelHooksTimeout DWORD值设置为较大的值。
请记住,C#的荣耀之一是,如果发生垃圾回收,那么即使是简单的语句也可能会花费非常长的时间。这(或其他线程加载的CPU)可能解释了问题的间歇性。
关于c# - 是什么导致Windows解除低级(全局)键盘 Hook 的钩子(Hook)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2655278/