最近编程碰到一个有意思的情况,在一个线程中用CreateProcess创建一个子进程cmd,cmd的参数中有两个可执行文件名A和B,即cmd启动后A进程和B进程用管道连接。对A和B而言,cmd是父进程;对B进程而言,A是输入进程。在任务管理器中,结束cmd后,A和B仍然存在,即子进程没有自动跟着结束;结束A后,cmd和B跟着结束;结束B后,cmd和A仍然存在。
如果新建一个批处理文件,把包含A和B的命令的参数放入批处理文件中,双击后可以执行,点击控制台关闭按钮A和B都能退出,和任务管理器中的表现方式略有不同。
在程序中调用CreateProcess时通过PROCESS_INFORMATION返回的只有父进程的句柄和ID,这岂不是很坑爹?难道眼睁睁地看着子进程巍然不动,任凭你怎么对父进程的handle调用TerminateProcess。后来想想,我的大脑可能像线程一样阻塞了,通过父进程取得每个子进程的handle,然后对每个进程handle都TerminateProcess不就可以了吗?
万能的google让我搜到一段代码,让我知道了从没注意过的Windows API,看懂并修改一下这段代码就可以解决自己的问题了
bool __fastcall KillProcessTree(DWORD myprocID, DWORD dwTimeout)
{
bool bRet = true;
HANDLE hWnd;
PROCESSENTRY32 pe;
memset(&pe, 0, sizeof(PROCESSENTRY32));
pe.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnap = :: CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (::Process32First(hSnap, &pe))
{
BOOL bContinue = TRUE;
// kill child processes
while (bContinue)
{
if (pe.th32ParentProcessID == myprocID)
{
ShowMessage ("Gleich - KILL PID: " + AnsiString(pe.th32ProcessID));
// Rekursion
KillProcessTree(pe.th32ProcessID, dwTimeout);
HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
if (hChildProc)
{
GetWindowThreadProcessId(hWnd, &myprocID);
// CLOSE Message s
PostMessage(hWnd, WM_CLOSE, 0, 0) ;
if (WaitForSingleObject(hChildProc, dwTimeout) == WAIT_OBJECT_0)
bRet = true;
else
{
bRet = TerminateProcess(hChildProc, 0);
}
::CloseHandle(hChildProc);
}
}
bContinue = ::Process32Next(hSnap, &pe);
}
// kill the main process
HANDLE hProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, myprocID);
if (hProc)
{
::TerminateProcess(hProc, 1);
::CloseHandle(hProc);
}
}
return bRet;
}