Terminate a process tree (C for Windows)

﹥>﹥吖頭↗ 提交于 2019-11-27 08:56:16
Mike Marshall

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);
    }       
}

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

Michael

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;
}

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.

@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);
    }
}

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!