为explorer.exe主窗口设置WH_CALLWNDPROC钩子后发消息触发崩溃?
问题原因
核心问题出在你发送的WM_USER + 1消息的处理逻辑上:
WM_USER(0x0400)起始范围的消息属于窗口类私有消息,不同窗口类对这个范围的消息定义完全不同,仅用于窗口类内部逻辑使用,没有全局统一的含义。- 你给顶层窗口(比如Explorer的主窗口)发送
WM_USER +1时,该窗口的原生窗口过程会按照自己内部的定义解析这个消息,你传入的wParam=0、lParam=0完全不符合它的预期,触发非法访问、非法操作等异常,最终导致崩溃。 - 子窗口不崩溃只是巧合:刚好你选中的子窗口对
WM_USER +1没有定义处理逻辑,或者参数0刚好符合它的处理要求,所以没有触发异常。
你补充的报错信息也可以佐证这个判断:
An outgoing call cannot be made since the application is dispatching an input-asynchronous call:Explorer处理你伪造的WM_USER +1时,尝试执行COM跨线程调用,但当前处于异步输入消息调度上下文,COM禁止此类操作,抛出异常。The operation is not permitted because the calling application is not the owner of the data on the clipboard:异常的消息处理逻辑触发了Explorer的剪贴板操作,此时Explorer并不持有剪贴板所有权,操作失败。
解决方案
任选一种即可解决崩溃问题:
- 更换自定义消息范围:不要使用
WM_USER范围的消息做跨进程自定义通信,改用WM_APP(0x8000)起始的消息范围,这个范围的消息是预留为应用程序全局使用的,不会和窗口类私有消息冲突,修改发送的消息为WM_APP +1即可。 - 钩子中拦截自定义消息:在你的
wmProcCallback中识别到你自己发送的WM_USER +1消息后,直接返回,不要调用CallNextHookEx,这样消息就不会传递给原窗口过程,也就不会触发原生逻辑的异常:
LRESULT CALLBACK wmProcCallback(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= HC_ACTION) { PCWPSTRUCT cwpStruct = (PCWPSTRUCT)lParam; switch (cwpStruct->message) { case WM_USER + 1: logfile << "WM_USER+1 Message received" << std::endl; // 直接返回,不传递给后续钩子和原窗口过程 return 0; } } return CallNextHookEx(NULL, nCode, wParam, lParam); }
内容的提问来源于stack exchange,提问作者Nur1
相关产品推荐
相关产品推荐

