在我的代码完成运行之前,如何才能阻止事件传递到 GUI?

发布于 2024-09-03 00:54:47 字数 1025 浏览 8 评论 0原文

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

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 是不安全的code> 从钩子函数外部,这是真的吗?

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

I installed a global mouse hook function like this:

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

The hook function looks like this:

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

Now, my problem is that I cannot control how long the 'do interesting stuff' part takes exactly. In particular, it might take longer than the LowLevelHooksTimeout defined in the Windows registry. This means that, at least on Windows XP, the system no longer delivers mouse events to my hook function. I'd like to avoid this, but at the same time I need the 'do interesting stuff' part to happen before the target GUI receives the event.

I attempted to solve this by doing the 'interesting stuff' work in a separate thread so that the mouseEventHookFn above can post a message to the worker thread and then do a return 1; immediately (which ends the hook function but avoids that the event is handed to the GUI). The idea was that the worker thread, when finished, performs the CallNextHookEx call itself.

However, this causes a crash inside of CallNextHookEx (in fact, the crash occurs inside an internal function called PhkNextValid. I assume it's not safe to call CallNextHookEx from outside a hook function, is this true?

If so, does anybody else know how I can run code (which needs to interact with the GUI thread of an application) before the GUI receives the event and avoid that my hook function blocks too long?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

感性 2024-09-10 00:54:47

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

我相信这是真的。

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

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

assume it's not safe to call CallNextHookEx from outside a hook function, is this true?

I believe this is true.

Since there is a finite number of operations that you can receive through your low-level mouse hook, you could just put them onto a queue to be re-posted to the receiving window once your long-running operation has finished. If you put your long-running on another thread, you'll not 'lock up' the UI, but merely 'eat' or 'defer' the user actions. Return 1 to prevent other hooks happening. Use a boolean flag to signify whether you're collecting events (because your long-running operation has to run yet) or re-posting them (and thus shouldn't hook them).

There aren't likely to be (m)any other low-level hooks in the system that you're cancelling, but you should test this mechanism thoroughly in your situation. I have used it only to block operations before (kill right-mouse-click) rather than defer them.

天涯离梦残月幽梦 2024-09-10 00:54:47

没有修复,你必须使你的代码更快。这些钩子可能对用户界面的响应能力非常不利,Windows 会确保将行为不端的钩子放入地窖。即使超时是可配置的,也永远不会被记录下来。这首先就违背了暂停的目的。

No fix, you'll have to make your code faster. These hooks are potentially very detrimental to the user interface responsiveness, Windows makes sure that a misbehaving one gets put in the cellar. Even if the timeout were configurable, it would never be documented. That would defeat the purpose of having a timeout in the first place.

尐偏执 2024-09-10 00:54:47

为什么要使用鼠标事件挂钩?您是一般性地挂钩鼠标还是仅针对特定窗口?如果它是针对特定窗口,那么您需要 - 而不是使用挂钩 - 实际上对目标窗口进行子类化。

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

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

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

Why are you using a mouse event hook? are you hooking the mouse generally or just for a specific window? If it is for a specific window then you need to - instead of using a hook - actually subclass the target window.

This is normally a 2 stage process - hooks always need to be in dll's as the hook needs to be executed in the context of the process (and thread) thats actually handling the message.

So you start by writing a hook dll that, when sent a message, calls SetWindowLong on an HWND to replace the GWL_WINDOWPROC with your new window proc.

In your WindowProc you can take as long as you want to handle messages.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文