检测 SetWindowsHookExA WH_MOUSE_LL 分离/脱钩
Detect SetWindowsHookExA WH_MOUSE_LL detachment / unhooking
我有一个小 Python 脚本,它收集关于我在 Windows 机器上的键盘和鼠标使用情况的统计信息。
我通过 windll.user32.SetWindowsHookExA(win32con.WH_MOUSE_LL, mouse_pointer, win32api.GetModuleHandle(None), 0)
设置了它。我写这篇文章是为了让您可以看到我正在使用哪个 API。它也可以是一个 C++ 程序。
它工作得很好,有一个例外:当我使用 Android Studio 编译应用程序时,我的 4 核 Core i7 在所有内核、鼠标和 OS 通常变得无响应,这是 Android Studio 的一个已知问题。
通常,当如此高的 CPU 负载发生几秒钟 (4+) 时,WH_MOUSE_LL 挂钩会被 OS 分离,就好像它在说 "Nope, we don't have time for you, we're unregistering you"
我不会将此归咎于 Python,因为我还有一个名为 PowerMixer 的音量管理器,它显然还注册了一个鼠标挂钩,以便它可以跟踪鼠标滚轮在降低任务栏(explorer.exe Shell_TrayWnd)并且此应用程序在编译后也失去了使用该鼠标挂钩的能力。
此外,当我编译并不断滚动滚轮(只是为了好玩)时,计算机开始发出哔哔声,就像非常低级的系统哔哔声一样,然后键盘挂钩也被取消注册。
如何通过 Windows API 检测我的挂钩是否脱落/脱钩?我不需要 Python 具体答案,只需要有关使用 Win32 API 处理此问题的正确方法的信息。
SetWindowsHookEx documentation 的 备注 部分说:
If the hook procedure times out, the system passes the message to the
next hook. However, on Windows 7 and later, the hook is silently
removed without being called. There is no way for the application to
know whether the hook is removed.
我在这里运气不好吗?
更新:几周后,我只想告诉大家,Hans Passan 的建议非常有效。我推荐这个。虽然 10.000 毫秒似乎有点高,但我已将其设置为该值并且没有任何负面影响。这是在几分钟内解决整个系统问题的方法。
How can I detect via the Windows API if my hooks got detached / unhooked?
没有直接的方法,您自己的问题引用了支持它的 MSDN 文档:
If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.
但是,间接 方法可能是让您的钩子跟踪上次调用它的时间,然后您的主要 app/script 可以调用 GetLastInputInfo()
periodically and compare that time to your tracked time. If the difference is a significant margin higher than the hook timeout that is stored in the Registry (see the documentation), 很有可能你的钩子不见了。
下面的 MSDN 博客解释了 hook 超时的详细信息:
Global hooks getting lost on Windows 7
但是,最重要的是,它指出:
My recommendation is that low level hooks should be avoided whenever possible. If you are monitoring keystrokes (and not trying to block them), you can get the keyboard input via Raw Input. This is lighter weight than hooks, won’t affect other apps’ responsiveness, and won’t be turned off if the app isn’t responsive.
这与 Microsoft 在 LowLevelMouseProc()
and LowLevelKeyboardProc()
文档中的建议相同:
If the application must use low level hooks, it should run the hooks on a dedicated thread that passes the work off to a worker thread and then immediately returns. In most cases where the application needs to use low level hooks, it should monitor raw input instead. This is because raw input can asynchronously monitor mouse and keyboard messages that are targeted for other threads more effectively than low level hooks can. For more information on raw input, see Raw Input.
我有一个小 Python 脚本,它收集关于我在 Windows 机器上的键盘和鼠标使用情况的统计信息。
我通过 windll.user32.SetWindowsHookExA(win32con.WH_MOUSE_LL, mouse_pointer, win32api.GetModuleHandle(None), 0)
设置了它。我写这篇文章是为了让您可以看到我正在使用哪个 API。它也可以是一个 C++ 程序。
它工作得很好,有一个例外:当我使用 Android Studio 编译应用程序时,我的 4 核 Core i7 在所有内核、鼠标和 OS 通常变得无响应,这是 Android Studio 的一个已知问题。
通常,当如此高的 CPU 负载发生几秒钟 (4+) 时,WH_MOUSE_LL 挂钩会被 OS 分离,就好像它在说 "Nope, we don't have time for you, we're unregistering you"
我不会将此归咎于 Python,因为我还有一个名为 PowerMixer 的音量管理器,它显然还注册了一个鼠标挂钩,以便它可以跟踪鼠标滚轮在降低任务栏(explorer.exe Shell_TrayWnd)并且此应用程序在编译后也失去了使用该鼠标挂钩的能力。
此外,当我编译并不断滚动滚轮(只是为了好玩)时,计算机开始发出哔哔声,就像非常低级的系统哔哔声一样,然后键盘挂钩也被取消注册。
如何通过 Windows API 检测我的挂钩是否脱落/脱钩?我不需要 Python 具体答案,只需要有关使用 Win32 API 处理此问题的正确方法的信息。
SetWindowsHookEx documentation 的 备注 部分说:
If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.
我在这里运气不好吗?
更新:几周后,我只想告诉大家,Hans Passan 的建议非常有效。我推荐这个。虽然 10.000 毫秒似乎有点高,但我已将其设置为该值并且没有任何负面影响。这是在几分钟内解决整个系统问题的方法。
How can I detect via the Windows API if my hooks got detached / unhooked?
没有直接的方法,您自己的问题引用了支持它的 MSDN 文档:
If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.
但是,间接 方法可能是让您的钩子跟踪上次调用它的时间,然后您的主要 app/script 可以调用 GetLastInputInfo()
periodically and compare that time to your tracked time. If the difference is a significant margin higher than the hook timeout that is stored in the Registry (see the documentation), 很有可能你的钩子不见了。
下面的 MSDN 博客解释了 hook 超时的详细信息:
Global hooks getting lost on Windows 7
但是,最重要的是,它指出:
My recommendation is that low level hooks should be avoided whenever possible. If you are monitoring keystrokes (and not trying to block them), you can get the keyboard input via Raw Input. This is lighter weight than hooks, won’t affect other apps’ responsiveness, and won’t be turned off if the app isn’t responsive.
这与 Microsoft 在 LowLevelMouseProc()
and LowLevelKeyboardProc()
文档中的建议相同:
If the application must use low level hooks, it should run the hooks on a dedicated thread that passes the work off to a worker thread and then immediately returns. In most cases where the application needs to use low level hooks, it should monitor raw input instead. This is because raw input can asynchronously monitor mouse and keyboard messages that are targeted for other threads more effectively than low level hooks can. For more information on raw input, see Raw Input.