即使在异常终止时,如何确保调用 UnhookWindowsHookEx?

Posted

技术标签:

【中文标题】即使在异常终止时,如何确保调用 UnhookWindowsHookEx?【英文标题】:How can I ensure that UnhookWindowsHookEx is called even upon abnormal termination? 【发布时间】:2010-12-18 16:09:12 【问题描述】:

不幸的是,MSDN 对它不够清楚。我正在编写一个使用全局钩子的程序,我担心如果程序异常终止(崩溃、被用户杀死等)会发生什么。

    当进程终止时,Windows 是否会自动解除进程安装的全局挂钩?

    如果没有,是否可以在另一个进程中调用 UnhookWindowsHookEx() 来释放挂钩? (如果检测到安装程序进程已死,我正在考虑在挂钩线程中执行此操作。)

    如果答案是“否”和“否”,那么在安装程序终止时让全局挂钩处于活动状态会不会很危险?处理这种情况的标准方法是什么?

    我在 MSDN 中读到 UnhookWindowsHookEx() 不会释放在其他进程中加载​​的 dll,但它没有说明何时释放 dll。 This article in CodeProject 似乎表明当第一条消息到达挂钩线程时,dll 未映射(在相应的进程中),因此它大约在 UnhookWindowsHookEx() 调用之后。是真的吗?

谢谢。

【问题讨论】:

【参考方案1】:
    是的,当一个进程终止时,系统会在它之后进行清理——所有句柄都被隐式关闭。 不,不是,而且您也不需要这样做。 (是,不是,不是,不是,不是) 我不明白为什么这里涉及的另一个进程中加载​​了 DLL。 (编辑:我最初想的是一个系统范围的钩子,例如CBTProc——如果你的钩子是每个进程的,那可能会有所不同)如果你正在处理类似@中指示的链接的东西Hans 的评论,您已经将自己的 DLL 注入到目标进程中,那么您应该将功能用于卸载 DLL 中的钩子,而不是将其正确操作绑定到您的应用程序。 (即,如果在 DLL 中将消息发送回您的应用程序失败,那么您的 DLL 应该决定自行卸载)/EDIT 当 DLL 在另一个进程中加载​​时,由该进程执行释放.

【讨论】:

您的第 4 点不准确,全局挂钩需要将带有挂钩回调的 DLL 注入目标进程。取消挂钩还涉及再次卸载该 DLL。关键是这是通过消息循环在进程本身内部同步的。 @Hans:这取决于钩子的类型。系统范围的挂钩不会将您的 DLL 注入目标进程。显然,如果您已将 DLL 注入该目标进程,那么该进程将成为释放它的进程(这就是我上面的第二句话所说的)。 不,这样真的不行。很复杂,很高兴这是你的答案,而不是我的 :) 这本来就是 ​​Just Works™。 @Hans:那么它是如何工作的呢? Bill 想知道他是否是个白痴 这是一种恭维,抱歉我搞砸了。一个 CBT 钩子是一个全局钩子。它确实是系统范围的,确实需要注入。好吧,根据 SetWindowsHookEx() 调用参数,指定线程不会使其成为全局线程。【参考方案2】:

如果您的进程终止,则隐式调用 UnhookWindowsHookEx 并删除您的挂钩。收到新消息后,消息处理代码会卸载 .dll。因此,一些几乎从不接收任何消息的后台进程可能在您的钩子被移除后很长时间仍保持库锁定。广播 WM_NULL 消息通常会有所帮助。我喜欢脱钩后发送几次。

SendNotifyMessage(HWND_BROADCAST, WM_NULL, 0, 0);

【讨论】:

以上是关于即使在异常终止时,如何确保调用 UnhookWindowsHookEx?的主要内容,如果未能解决你的问题,请参考以下文章

GCC(libstdc++)运行时如何决定在异常处于活动状态时终止()

SEH 结构化异常

如果在它使用的模块中引发异常,我如何防止我的 perl 脚本终止?

确保脚本在用户中止时退出

大型机 CEE3DD 异常终止 - CEE3501S - 在 COBOL 动态调用中找不到模块

如何在退出时执行异步操作