C#如何高效检测新进程启动及可见主窗口打开?
高效检测带可见主窗口的新进程启动
用SetWinEventHook做事件驱动监听(最优方案)
这是最省资源的方式,只有当新窗口创建或显示时才触发回调,完全无需轮询:
- 监听
EVENT_OBJECT_CREATE和EVENT_OBJECT_SHOW两个事件,指定OBJID_WINDOW目标对象,只捕获窗口相关的事件 - 在回调里做三层过滤:窗口可见(
IsWindowVisible)、是主窗口(GetParent返回NULL)、句柄有效(IsWindow),再通过GetWindowThreadProcessId拿到所属进程ID - 代码示例:
HWINEVENTHOOK g_windowHook = nullptr; void CALLBACK WinEventCallback(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG objId, LONG childId, DWORD threadId, DWORD eventTime) { // 只处理顶级窗口事件 if (objId != OBJID_WINDOW || childId != CHILDID_SELF) return; if ((event == EVENT_OBJECT_CREATE || event == EVENT_OBJECT_SHOW) && IsWindow(hwnd) && IsWindowVisible(hwnd) && GetParent(hwnd) == nullptr) { DWORD processId = 0; GetWindowThreadProcessId(hwnd, &processId); // 这里执行你的钩子重启逻辑 } } // 初始化钩子(放在程序启动处) g_windowHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_SHOW, nullptr, WinEventCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // 程序退出时释放钩子 UnhookWinEvent(g_windowHook);
- 注意:
WINEVENT_SKIPOWNPROCESS可以跳过自身进程的窗口事件,避免不必要的触发;钩子要在程序退出时正确释放,防止内存泄漏
辅助过滤逻辑(避免无效窗口)
如果还想排除系统工具窗口、弹窗类窗口,可以再加个判断:
// 排除工具窗口(比如状态栏、工具栏的独立窗口) if ((GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) != 0) { return; }
为什么之前的轮询方法CPU占用高?
不管是EnumWindows还是遍历进程快照,轮询都会定期占用CPU时间片,哪怕间隔几秒,长期运行下来也会有持续的占用。事件驱动的方式只有在触发条件满足时才会执行代码,CPU占用几乎可以忽略。
内容的提问来源于stack exchange,提问作者tar
相关产品推荐
相关产品推荐

