简体   繁体   English

终止进程树(Windows 的 C)

[英]Terminate a process tree (C for Windows)

This has been asked before but I can't find a definitive answer, in code.之前有人问过这个问题,但我无法在代码中找到明确的答案。

I open a process, ProcessA (with PID 1234).我打开一个进程,ProcessA(PID 1234)。 This process opens a child process, ProcessAB (PID 5678).该进程打开一个子进程 ProcessAB (PID 5678)。 After I'm done I terminate ProcessA but I still have the lingering of ProcessAB.完成后,我终止了 ProcessA,但 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.代码表示赞赏。

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获取您的主进程 ID
  2. Call CreateToolhelp32Snapshot to enumerateall the processes on the system调用CreateToolhelp32Snapshot枚举系统上的所有进程
  3. Check the th32ParentProcessID member of the PROCESSENTRY32 structure on each process, if it matches your parent ID, then terminate the process (using TerminateProcess )检查每个进程的 PROCESSENTRY32 结构的 th32ParentProcessID 成员,如果它与您的父 ID 匹配,则终止进程(使用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.它是 Windows 必须提供的最接近 unix“进程组”的东西。

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 .与 unix 不同,在撰写本文时,“作业对象”无法嵌套 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).这意味着如果父母为孩子创建作业对象,则该孩子的所有孩子自己都不能使用作业对象(恕我直言,这是/严重/限制,就像只允许一级子目录的文件系统一样)。

To kill a whole tree with ALL:!!用 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;
}

@mjmarsh answers needs recursion for the homebrew case, otherwise it is the right one. @mjmarsh 的答案需要自制程序案例的递归,否则它是正确的。 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);
    }
}

There's How To Kill a Process Tree , but it's in C#.How To Kill a Process Tree ,但它是在 C# 中。 I don't think it's too hard to port that to C.我认为将其移植到 C 并不难。

See NtQueryInformationProcess Function and TerminateProcess Function .请参阅NtQueryInformationProcess 函数TerminateProcess 函数

The following is for Linux, but I hope it helps for Windows with some adaptation.以下是针对 Linux 的,但希望对 Windows 有所适配有所帮助。

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. fork()时,保存返回值,即子进程的pid,然后在父进程即将退出时,kill()该pid。

If you have multiple child processes, you can send the kill to the process group.如果您有多个子进程,则可以将 kill 发送到进程组。 By default, the child processes have the same pgid as the parent.默认情况下,子进程与父进程具有相同的 pgid。

Pure C (if you don't count the exe call as non-C code) very quick & dirty approach: use system() with taskkill.exe纯 C(如果您不将 exe 调用算作非 C 代码)非常快速且肮脏的方法:将system()taskkill.exe一起使用

/* Kill process tree in C on windows: quick and very dirty solution */
void killtree(DWORD pid, char force, char tree) {
  char cmd[1024];
  char *forceflag = force ? " /F" : "";
  char *treeflag = tree ? " /T" : "";
  sprintf(cmd, "taskkill%s%s /PID %lu", forceflag, treeflag, pid);
  system(cmd);

  /* optional additional code-- see below */
  if(process_is_running(pid)) {
    fprintf(errlog, "couldn't kill %lu\r\n", pid);
    fflush(errlog);
  }
}

/* if you want, you might also want to use process_is_running() */
static char process_is_running(DWORD pid) {
  if(!pid)
    return 0;
  HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
  DWORD ret = WaitForSingleObject(process, 0);
  CloseHandle(process);
  return ret == WAIT_TIMEOUT;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM