2013-12-09 180 views
1

我有一個問題,但沒有解決方案。如何殺死進程窗口的所有遞歸子進程

我的程序運行並創建一些進程,但進程繼續創建另一個進程。 我不知道如何讓所有的孩子全部殺死。

我用CreateToolhelp32Snapshot函數來獲取所有父母是我的程序(mainthread)的孩子......並繼續從每個mainthread的孩子中獲取所有孩子。

hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

如果我用這個解決方案,性能是非常低的,因爲我已經在第一時間全部過程的PID,這樣我就可以不用再打電話CreateToolhelp32Snapshot

我可以做哪些最好的解決辦法獲取流程窗口的所有遞歸子項?

+0

做什麼? – manuell

+0

我的回答有幫助嗎? – manuell

+0

嗨@quanrock請給予反饋。你有沒有設法使用喬布斯,或使用我的代碼? – manuell

回答

2

首先,看看Win32 Job API。一種功能是能夠自動終止屬於同一作業的所有進程。請參閱TerminateJobObject API。

編輯:陳先生剛纔博客有關這個確切的主題。 Destroying all child processes (and grandchildren) when the parent exits

然後,你的問題。你可以爲所有當前正在運行的進程構建一個std :: map,關鍵是PID,值是子進程的std :: vector。然後你可以在地圖上遞歸來終止一個進程和他所有的孩子。

// KillChildren.cpp 
// Usage: pass a PID a argument 

#include <Windows.h> 
#include <TlHelp32.h> 
#include <vector> 
#include <map> 

typedef std::vector<DWORD> VEC_CHILDS; 
typedef VEC_CHILDS::iterator IT_CHILDS; 
typedef std::map<DWORD, VEC_CHILDS> MAP_PIDS; 
typedef MAP_PIDS::iterator IT_PIDS; 

void KillProcess(DWORD dwPID) { 

    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, dwPID); 
    if (hProcess == NULL) { 
     printf("Cant't OpenProcess for PID %u, Reason %u\n", dwPID, GetLastError()); 
     return; 
    } 
    BOOL bWin32Success = TerminateProcess(hProcess, 0); 
    if (bWin32Success == 0) { 
     printf("Cant't TerminateProcess for PID %u, Reason %u\n", 
       dwPID, GetLastError()); 
    } else { 
     DWORD dwRetVal = WaitForSingleObject(hProcess, 2000); 
     if (dwRetVal != WAIT_OBJECT_0) { 
      printf("Failed to Wait for Process Termination for PID %u," 
        "RetVal %u Reason %u\n", dwPID, dwRetVal, GetLastError()); 
     } else { 
      printf("Process %u Terminated\n", dwPID); 
     } 
    } 
    CloseHandle(hProcess); 

} 

void KillChilds(DWORD dwParentPID, MAP_PIDS & mPids) { 
    IT_PIDS it = mPids.find(dwParentPID); 
    if (it == mPids.end()) return; 
    VEC_CHILDS & vChilds = it->second; 
    for (IT_CHILDS itChild = vChilds.begin(); itChild != vChilds.end(); ++itChild) { 
     KillChilds(*itChild, mPids); 
    } 
    KillProcess(dwParentPID); 
} 

// usage: PID as first arg 
int main(int argc, char* argv[]) { 

    if (argc <= 1) return -1; 
    DWORD dwPID = atoi(argv[ 1 ]); 

    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    if (hProcessSnap == INVALID_HANDLE_VALUE) return -1; 

    // build PID list with children 
    PROCESSENTRY32 pe32; 
    pe32.dwSize = sizeof(PROCESSENTRY32); 
    if(!Process32First(hProcessSnap, &pe32)) { 
     CloseHandle(hProcessSnap); 
     return -1; 
    } 
    MAP_PIDS mPids; 
    do { 
     // Add as a Parent, with no child, yet, if not already done 
     IT_PIDS it = mPids.find(pe32.th32ProcessID); 
     if (it == mPids.end()) mPids[ pe32.th32ProcessID ] = VEC_CHILDS(); 
     // Process the Parent 
     it = mPids.find(pe32.th32ParentProcessID); 
     if (it == mPids.end()) { 
      // unknown parent, add it with one child 
      VEC_CHILDS vChilds; 
      vChilds.push_back(pe32.th32ProcessID); 
      mPids[ pe32.th32ParentProcessID ] = vChilds; 
     } else { 
      // Parent already here, add one more child 
      it->second.push_back(pe32.th32ProcessID); 
     } 
    } while (Process32Next(hProcessSnap, &pe32)); 
    CloseHandle(hProcessSnap); 

    KillChilds(dwPID, mPids); 
    return 0; 

} 

如果你想測試上面的程序,這裏是一個小的進程樹生成要殺死所有的子進程時,(因爲)你的第一個進程終止

// CreateChildren.cpp 
// beware, messing may be 'fork bombing' 

#include <Windows.h> 

int main(int argc, char* argv[]) { 

    srand(GetTickCount()); 
    // always childs if args 
    if (argc == 0) { 
     int iRandom = rand(); 
     if (iRandom % 3) Sleep(INFINITE); 
    } 

    char szFullExeName[ MAX_PATH ]; 
    DWORD dwCopied = GetModuleFileName(NULL, szFullExeName, sizeof(szFullExeName)); 
    if (dwCopied == 0) return -1; 

    STARTUPINFO si; 
    memset(&si, 0, sizeof(si)); 
    si.cb = sizeof(si); 
    PROCESS_INFORMATION pi; 
    int ChildCount = rand() % 3; 
    while (ChildCount--) { 
     BOOL bWin32Success = CreateProcess(szFullExeName, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 
     if (bWin32Success) { 
      CloseHandle(pi.hThread); 
      CloseHandle(pi.hProcess); 
     } 
    } 

    Sleep(INFINITE); 
    return 0; 

} 
+1

使用工作是解決這個問題的方法。枚舉通過快照可以留下一些進程提前終止(打破鏈)的空白。並且不保證新流程不會重複使用舊的PID。 –

+0

@joshpoley我同意100%。 – manuell