在代码完成运行之前,如何防止事件传递到GUI?

时间:2010-05-26 12:41:31

标签: c++ windows winapi setwindowshookex

我安装了一个像这样的全局鼠标钩子函数:

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线程交互) ?

3 个答案:

答案 0 :(得分:1)

没有问题,你必须加快代码的速度。这些钩子可能对用户界面响应性非常不利,Windows确保将行为不端的人放入地窖。即使超时是可配置的,也永远不会记录。这将首先打败暂停的目的。

答案 1 :(得分:1)

为什么使用鼠标事件挂钩?你一般是挂钩鼠标还是只是为了一个特定的窗口?如果是针对特定窗口,则需要 - 而不是使用钩子 - 实际上是目标窗口的子类。

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

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

在您的WindowProc中,只要您想处理消息,就可以使用。

答案 2 :(得分:1)

  

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

我相信这是真的。

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

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