You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 15:05:30