如何在C++ WinApp中监听其他前台应用的关闭事件?
问题根因
你现在监听的EVENT_OBJECT_DESTROY事件会在所有UI元素(包括子控件、菜单、临时弹窗等)销毁时触发,并不是只有主窗口关闭才会触发,所以会出现无意义的回调。
修复方案
- 回调函数内增加多层过滤逻辑,只保留符合「前台应用主窗口关闭」的事件
- 搭配
EVENT_SYSTEM_FOREGROUND事件记录当前前台窗口的句柄,进一步缩小触发范围
具体修改代码
首先定义全局变量存储当前前台窗口句柄:
HWND g_currentForegroundHwnd = NULL;
修改窗口事件回调逻辑:
void CALLBACK WinEventProc( HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime ) { // 过滤子控件事件,只处理窗口本身的事件 if (idObject != OBJID_CLIENT || idChild != CHILDID_SELF) { return; } // 过滤非顶级窗口(排除子窗口、临时弹窗等) if (GetParent(hwnd) != NULL) { return; } // 过滤自身应用的窗口 DWORD currentPid = GetCurrentProcessId(); DWORD winPid = 0; GetWindowThreadProcessId(hwnd, &winPid); if (winPid == currentPid) { return; } // 过滤不可见窗口 if (!IsWindowVisible(hwnd)) { return; } if (event == EVENT_SYSTEM_FOREGROUND) { // 记录当前前台窗口 g_currentForegroundHwnd = hwnd; return; } if (event == EVENT_OBJECT_DESTROY) { // 只处理当前前台窗口的销毁事件 if (hwnd == g_currentForegroundHwnd) { handleProcess(hwnd); // 处理完成后清空前台窗口记录 g_currentForegroundHwnd = NULL; } return; } }
修改钩子注册逻辑,同时注册前台窗口切换和窗口销毁事件:
... // 注册窗口销毁事件钩子 winDestructionHook = SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY, NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); // 注册前台窗口切换事件钩子 foregroundHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); ...
注意事项
- 程序退出时要调用
UnhookWinEvent释放两个钩子,避免资源泄漏 - 如果需要捕获无标题栏的特殊应用窗口,可以去掉主窗口样式校验逻辑,只保留父窗口为空的判断即可
- 该方案支持所有常规关闭操作的监听,包括右上角叉号、
Ctrl+F4、任务管理器结束进程等触发主窗口销毁的场景
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

