Завершить дерево процессов (C для Windows)

Это задано раньше, но я не могу найти окончательный ответ в коде.

Открываю процесс ProcessA (с PID 1234). Этот процесс открывает дочерний процесс ProcessAB (PID 5678). После того, как я закончил, я завершаю ProcessA, но у меня все еще есть задержка ProcessAB.

Как закончить все дерево процессов? Что я имею в виду, как я могу убедиться, что, если я закончу процесс, который я открыл, я также завершаю все связанные процессы?

Спасибо

Оценивается код.

Ответ 1

Отметьте этот поток для группировки процессов в рамках "задания".

Если это не сработает для вас, домашний подход может выглядеть следующим образом:

  • Получить свой основной идентификатор процесса
  • Вызов CreateToolhelp32Snapshot для перечисления всех процессов в системе
  • Проверьте член th32ParentProcessID структуры PROCESSENTRY32 для каждого процесса, если он соответствует вашему родительскому идентификатору, затем завершите процесс (используя TerminateProcess)
  • После того, как все дети завершены, завершите основной процесс

Пример кода:

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

Ответ 2

Используйте Объекты работы.

Это самая близкая вещь для группы процессов unix, которую могут предложить эти окна.

Объекты заданий позволяют указать, что дочерний процесс (и все его дочерние элементы) можно управлять вместе, например. за убийство. В отличие от unix, на момент написания "объекты задания" не могут быть вложенными. Это означает, что если родитель создает объект задания для дочернего элемента, все дочерние дочерние объекты не могут сами использовать объекты задания (который является ИМХО/серьезным/ограниченным ИМХО, как файловая система, которая разрешает только один уровень подкаталогов).

Ответ 3

Чтобы убить цельное дерево ВСЕ! Чайлдс:

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

Ответ 5

@mjmarsh ответы требуют рекурсии для дела доморощенного, иначе это правильный. Создание объектов задания лучше, чем ниже, если вы можете.

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

Ответ 6

Ниже приведено описание для Linux, но я надеюсь, что это поможет Windows с некоторой адаптацией.

Когда вы fork(), сохраните возвращаемое значение, которое является pid дочернего процесса, тогда, когда родитель собирается выйти, kill() pid.

Если у вас несколько дочерних процессов, вы можете отправить kill в группу процессов. По умолчанию дочерние процессы имеют тот же pgid, что и родительский.