1

我安装了一个全局鼠标钩子函数,如下所示:

mouseEventHook = ::SetWindowsHookEx( WH_MOUSE_LL, mouseEventHookFn, thisModule, 0 );

钩子函数如下所示:

RESULT CALLBACK mouseEventHookFn( int code, WPARAM wParam, LPARAM lParam )
{
    if ( code == HC_ACTION ) {
        PMSLLHOOKSTRUCT mi = (PMSLLHOOKSTRUCT)lParam;
        // .. do interesting stuff ..
    }
    return ::CallNextHookEx( mouseEventHook, code, wParam, lParam );
}

现在,我的问题是我无法控制“做有趣的事情”部分究竟需要多长时间。特别是,它可能需要比 Windows 注册表中定义的 LowLevelHooksTimeout 更长的时间。这意味着,至少在 Windows XP 上,系统不再将鼠标事件传递给我的钩子函数。我想避免这种情况,但同时我需要在目标 GUI 接收事件之前发生“做有趣的事情”部分。

我试图通过在一个单独的线程中做“有趣的东西”工作来解决这个问题,这样mouseEventHookFn上面就可以向工作线程发布一条消息,然后return 1;立即执行一个(这会结束钩子函数但避免将事件传递给 GUI )。这个想法是工作线程在完成后CallNextHookEx自己执行调用。

但是,这会导致内部崩溃CallNextHookEx(实际上,崩溃发生在名为 的内部函数内部PhkNextValid。我认为从挂钩函数外部调用是不安全的CallNextHookEx,这是真的吗?

如果是这样,是否有其他人知道我如何在 GUI 接收事件之前运行代码(需要与应用程序的 GUI 线程交互)避免我的钩子函数阻塞太久?

4

3 回答 3

1

没有修复,你必须让你的代码更快。这些钩子可能对用户界面的响应能力非常不利,Windows 会确保将行为不端的钩子放入地下室。即使超时是可配置的,也永远不会记录在案。这首先会破坏超时的目的。

于 2010-05-26T14:23:13.287 回答
1

为什么要使用鼠标事件挂钩?您是在一般情况下挂鼠标还是只为特定窗口挂鼠标?如果它是针对特定窗口的,那么您需要 - 而不是使用挂钩 - 实际上是目标窗口的子类。

这通常是一个 2 阶段的过程 - 钩子总是需要在 dll 中,因为钩子需要在实际处理消息的进程(和线程)的上下文中执行。

因此,您首先编写一个钩子 dll,当发送消息时,它会在 HWND 上调用 SetWindowLong 以用您的新窗口 proc 替换 GWL_WINDOWPROC。

在您的 WindowProc 中,您可以根据需要处理消息。

于 2010-05-26T22:44:50.513 回答
1

假设从钩子函数外部调用 CallNextHookEx 是不安全的,这是真的吗?

我相信这是真的。

由于您可以通过低级鼠标挂钩接收有限数量的操作,因此您可以将它们放入队列中,以便在长时间运行的操作完成后重新发布到接收窗口。如果您将长时间运行放在另一个线程上,您将不会“锁定”用户界面,而只会“吃掉”或“推迟”用户操作。返回 1 以防止发生其他钩子。使用布尔标志来表示您是在收集事件(因为您的长时间运行的操作必须运行)还是重新发布它们(因此不应挂钩它们)。

系统中不太可能有 (m) 任何其他您要取消的低级挂钩,但您应该在您的情况下彻底测试此机制。我只用它来阻止之前的操作(杀死鼠标右键单击)而不是推迟它们。

于 2010-05-26T23:44:02.713 回答