Terminate a process tree (C for Windows)
Check this thread for grouping processes within a "job".
If that does not work for you, a home grown approach might go as follows:
- Get your main process ID
- Call CreateToolhelp32Snapshot to enumerateall the processes on the system
- Check the th32ParentProcessID member of the PROCESSENTRY32 structure on each process, if it matches your parent ID, then terminate the process (using TerminateProcess)
- After all children are terminated, terminate the main process
Sample code:
DWORD myprocID = 1234; // your main process id
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)
{
// only kill child processes
if (pe.th32ParentProcessID == myprocID)
{
HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
if (hChildProc)
{
::TerminateProcess(hChildProc, 1);
::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);
}
}
To kill a whole tree with ALL!!! childs:
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;
}
Use Job Objects.
It's the closest thing to a unix 'process group' that windows has to offer.
Job Objects allow you to indicate a child process (and all its children) can be managed together, esp. for being killed. Unlike unix, as of this writing 'job objects' cannot be nested. Which means if a parent creates a job object for a child, all that child's children cannot themselves use Job Objects (which is a /severe/ limitation IMHO, like a file system that only allows one level of sub directories).
@mjmarsh answers needs recursion for the homebrew case, otherwise it is the right one. Creating job objects is better that the below when you can.
void KillProcessTree(DWORD myprocID)
{
PROCESSENTRY32 pe;
memset(&pe, 0, sizeof(PROCESSENTRY32));
pe.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (::Process32First(hSnap, &pe))
{
do // Recursion
{
if (pe.th32ParentProcessID == myprocID)
KillProcessTree(pe.th32ProcessID);
} while (::Process32Next(hSnap, &pe));
}
// kill the main process
HANDLE hProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, myprocID);
if (hProc)
{
::TerminateProcess(hProc, 1);
::CloseHandle(hProc);
}
}