我有一个.NET类库,它会旋转一个二级进程,该进程一直运行直到我处理掉该对象。
由于程序中存在一些遗留问题,我决定添加一个集成测试,以确保如果我让对象失效到GC / Finalization,那么该过程就会被删除。
但是,由于该进程是Mercurial命令行客户端,并且我的构建服务器已经将Mercurial作为其自身操作的一部分运行,因此我设想Mercurial在该测试开始时已经运行或者它已经启动的情况,并且在测试结束时仍然在运行,与构建服务器相关,而不是我的测试。
所以,我想确保我找到(或不是)我发现的Mercurial客户端,而不仅仅是当前正在运行的任何客户端。
所以问题是:
通过“查看”,我正在考虑使用Process.GetProcesses方法,但这不是必需的。
如果一个不同的问题更好,“如何找到我所有进程的所有子进程”,即。更容易回答,一个人绰绰有余。
我找到了这个页面:How I can know the parent process ID of a process?,但似乎我必须给它一个进程名称。如果我只是给它“hg”,对于我正在寻找的情况,这个问题是不是太模糊了?
答案 0 :(得分:18)
private static void KillAllProcessesSpawnedBy(UInt32 parentProcessId)
{
logger.Debug("Finding processes spawned by process with Id [" + parentProcessId + "]");
// NOTE: Process Ids are reused!
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Process " +
"WHERE ParentProcessId=" + parentProcessId);
ManagementObjectCollection collection = searcher.Get();
if (collection.Count > 0)
{
logger.Debug("Killing [" + collection.Count + "] processes spawned by process with Id [" + parentProcessId + "]");
foreach (var item in collection)
{
UInt32 childProcessId = (UInt32)item["ProcessId"];
if ((int)childProcessId != Process.GetCurrentProcess().Id)
{
KillAllProcessesSpawnedBy(childProcessId);
Process childProcess = Process.GetProcessById((int)childProcessId);
logger.Debug("Killing child process [" + childProcess.ProcessName + "] with Id [" + childProcessId + "]");
childProcess.Kill();
}
}
}
}
答案 1 :(得分:1)
虽然answer of mtijn可能是你能得到的最接近的,但真正的答案是:你做不到。
当中间级别的进程终止时,Windows不会维护一个真正的进程树,其中进程被重新组织。但是,Windows确实记住了父进程ID。
有问题的案例如下:
原始流程结构:
YourApp.exe
- SubApp.exe
- Second.exe
如果现在SubApp.exe终止,则不会更新Second.exe的父进程ID。新结果是
YourApp.exe
Second.exe
您可以使用SysInternals Process Explorer验证这一点。它能够将进程显示为树。启动CMD,然后键入start cmd
。在新窗口中,再次键入start cmd
。你将打开3个窗户。现在终止中间的那个。
答案 2 :(得分:1)
谢谢!从以前的 KillAllProcessesSpawnedBy 回答我做了这个:
public static void WaitForAllToExit(this Process process)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Process " +
"WHERE ParentProcessId=" + process.Id);
ManagementObjectCollection collection = searcher.Get();
if (collection.Count > 0)
{
foreach (var item in collection)
{
UInt32 childProcessId = (UInt32)item["ProcessId"];
if ((int)childProcessId != Process.GetCurrentProcess().Id)
{
Process childProcess = Process.GetProcessById((int)childProcessId);
WaitForAllToExit(childProcess);
}
}
}
process.WaitForExit();
}