Win32 c++ openprocess应该返回null,如果用户已经退出应用程序,但没有

Win32 C++ OpenProceess should return null if user has exited application but doesnt?

本文关键字:退出 应用程序 用户 如果 openprocess c++ null 返回 Win32      更新时间:2023-10-16

我有一个程序(作为后台进程运行),我在其中安装了一个钩子来捕获EVENT_SYSTEM_FOREGROUND事件(即-当用户在窗口之间切换时)。为钩子注册的回调基本上记录了用户从切换到的应用程序(进程exe文件名)以及他们将切换到的应用程序。

我想添加一些代码来检查他们从切换到的应用程序是否仍然活跃(如果不是,我们假设他们已经关闭了它,这就是将新窗口带入前台的原因)。我正在测试它的存在,尝试使用OpenProcess

创建前一个PID的句柄。
    //Check prev pid still exists - if not, assume the previous app has been closed
    HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid);
    if (hPrevProc==NULL){
        prevProcStillRunning=false;
    }
    else{
        CloseHandle(hPrevProc);
    }

上面代码的假设:
g_prevPid填充了一个PID -我已经验证了这个
prevProcStillRunning已初始化为true

上面代码的问题是,由于某种原因,即使用户退出了应用程序(例如notepad.exe)。在它们退出后的10秒内,这个测试仍然通过(即hPrevProc被初始化)。即使我可以在任务管理器中看到Notepad.exe进程已经消失(是的,我只打开了一个实例),不知何故,OpenProcess行仍然可以得到该PID的句柄。我猜不知何故PID实际上仍然存在,但它可能处于其终止的状态。我发现,如果这段代码再被调用几次,最终它将返回null。

我想找出一个更好的方法,我可以测试hPrevProc是否仍然是活跃的。我试图使用GetExitCodeProcess函数来测试这一点,但这似乎只是给我PID,我甚至不确定这在任何情况下是否是正确的方法。

感谢任何帮助。

进程终止后,至少在它有一个打开的句柄时,它在系统中存在。

了解进程是否仍然处于活动状态的唯一万无一失的方法是:

  • 确保进程不能退出代码STILL_ACTIVE (259)
  • 尝试打开进程(OpenProcess)->如果不能,则被终止
  • 读取退出进程代码(GetExitCodeProcess) ->如果不是STILL_ACTIVE,则进程终止。

你的代码可以变成:

//Check prev pid still exists - if not, assume the previous app has been closed
HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid);
if (hPrevProc==NULL){
    prevProcStillRunning=false;
}
else{
    DWORD cr;
    if ((GetExitCodeProcess(hPrevProc, &cr) == 0) || (cr != STILL_ACTIVE)) {
        prevProcStillRunning=false;
    }
    CloseHandle(hPrevProc);
}

无论如何,关闭GUI应用程序涉及不同的步骤:
  • GUI元素被销毁
  • 消息循环结束
  • 最终应用程序可以执行后台操作(将状态保存到文件等)
  • 主过程返回退出码
  • 系统知道应用程序被终止

事件将在主窗口关闭时发送,这可能在应用程序实际停止之前发生。Firefox就是一个很好的例子。如果您关闭窗口并立即尝试启动一个新进程,您将得到一个错误,因为即使UI消失了,进程仍然没有终止。更糟糕的是,当你关闭UI时,你会发现应用程序只是进入后台,并允许用户通过任务栏状态区图标上的动作再次打开UI (Shell_NotifyIcon及其回调)。这对于在后台工作的其他应用程序的服务(网络服务器、防火墙等)来说很常见。在这种情况下,UI消失了,但是进程不会终止。

TL/DR: UI分离到拥有它的进程终止之间的时间是可变的,取决于系统负载和进程关闭UI后的后台活动。你可以尝试使用延迟,但我不能保证任何事情。

可能某些进程(也许是您的?)仍然持有该进程的有效句柄。在对所有句柄调用CloseHandle之前,系统维护允许访问其进程数据的内部记录。这很重要,因为正如你所说,必须有可能在关闭的进程上调用GetExitCodeProcess,也有人可能想用WaitForSingleObject等待它停止。

也要小心pid,它们可以被重用——所以理论上你可以在其他新打开的进程上调用OpenProcess。

至于检查给定的进程是否不是僵尸,你可以尝试用EnumWindows枚举顶级窗口,并检查它们是否与给定的PID相关联(使用GetWindowThreadProcessID获取窗口的PID)。