views:

2208

answers:

4

This has been asked before but I can't find a definitive answer, in code.

I open a process, ProcessA (with PID 1234). This process opens a child process, ProcessAB (PID 5678). After I'm done I terminate ProcessA but I still have the lingering of ProcessAB.

How do I terminate the whole process tree? What I mean, how do I make sure that if I terminate the process I opened I am also terminating all the associated processes?

Thanks

Code is appreciated.

A: 

The following is for Linux, but I hope it helps for Windows with some adaptation.

When you fork(), save the return value, which is the pid of the child process, then when the parent is about to exit, kill() the pid.

If you have multiple child processes, you can send the kill to the process group. By default, the child processes have the same pgid as the parent.

Mike Mu
1) I wish i was working on Linux2) I wish windows had fork()3) The process I am opening is opening the child processes so I have no control over thatbut thanks anyway
wonderer
A: 

There's How To Kill a Process Tree, but it's in C#. I don't think it's too hard to port that to C.

See NtQueryInformationProcess Function and TerminateProcess Function.

eed3si9n
I tried converting that code yesterday but no luck.anyway, I am already using Ntquery and terminateprocess but those only take care of the parent and not the rest
wonderer
+3  A: 

Check this thread for grouping processes within a "job".

If that does not work for you, a home grown approach might go as follows:

  1. Get your main process ID
  2. Call CreateToolhelp32Snapshot to enumerateall the processes on the system
  3. Check the th32ParentProcessID member of the PROCESSENTRY32 structure on each process, if it matches your parent ID, then terminate the process (using TerminateProcess)
  4. 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, myprocID);

   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);
 }  
}
mjmarsh
hmmm this might work. let me see.
wonderer
I can't seem to get it right. DO you have a sample snippet? thanks
wonderer
Sorry, I had written that from memory. The first call should be CreateToolhelp32Snapshot, not EnumProcesses. Sample above.
mjmarsh
you need to get debug privileges to open the process but it seems to be working other than that. thanks
wonderer
A: 

To kill a hole 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;
}
Michael