分享

Terminate a process tree (C for Windows)

 quasiceo 2014-08-11

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.

asked Jul 23 '09 at 17:39
wonderer
95872251

5 Answers

up vote 6 down vote accepted

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, 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);
    }       
}
answered Jul 23 '09 at 17:49
mjmarsh
5,85812139

    
hmmm this might work. let me see. –  wonderer Jul 23 '09 at 18:33
    
I can't seem to get it right. DO you have a sample snippet? thanks –  wonderer Jul 23 '09 at 19:28
    
Sorry, I had written that from memory. The first call should be CreateToolhelp32Snapshot, not EnumProcesses. Sample above. –  mjmarsh Jul 24 '09 at 16:04
    
you need to get debug privileges to open the process but it seems to be working other than that. thanks –  wonderer Jul 30 '09 at 18:21

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).

answered May 26 '11 at 12:06
seriss
311

1  
Support for nesting job objects has been added to Windows 8 and Windows Server 2012. –  Esoteric Screen Name Aug 7 '12 at 16:08

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;
}
answered Jan 28 '10 at 10:42
Michael
311

    
You may not call GetWindowThreadProcessId with hWnd undefined. While the code definitely demonstrates a good idea to try to close windows nicely, it does not work. –  Alex Jul 10 '13 at 9:01

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.

answered Jul 23 '09 at 17:46
Eugene Yokota
43.3k24100166

    
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 Jul 23 '09 at 18:31

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.

answered Jul 23 '09 at 17:42
Mike Mu
60938

    
1) I wish i was working on Linux 2) I wish windows had fork() 3) The process I am opening is opening the child processes so I have no control over that but thanks anyway –  wonderer Jul 23 '09 at 18:30

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多