首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ 進程管理核心技術:CreateProcess 創建子進程、環境塊繼承、等待退出碼完整詳解

     編輯:VC 教學

Windows 進程是資源容器 (虛擬地址空間、句柄表、執行緒)。VC++ 透過 CreateProcess 創建子進程,實現多任務隔離、權限分離、穩定性保護。本文系統講解 CreateProcess 完整參數、啟動流程、環境變量繼承、WaitForSingleObject 同步等待、GetExitCodeProcess 獲取退出碼、錯誤處理最佳實踐。

CreateProcess 完整原型

BOOL CreateProcess(
    LPCTSTR lpApplicationName,        // 模組路徑 (NULL 時從命令列解析)
    LPTSTR  lpCommandLine,            // 完整命令列字串 (可修改)
    LPSECURITY_ATTRIBUTES lpProcessAttr,  // 進程安全屬性 (NULL=預設, 不可繼承)
    LPSECURITY_ATTRIBUTES lpThreadAttr,   // 執行緒安全屬性
    BOOL    bInheritHandles,          // TRUE: 子進程繼承父進程可繼承句柄
    DWORD   dwCreationFlags,          // 創建標誌
    LPVOID  lpEnvironment,            // 新環境塊指標 (NULL=繼承父進程)
    LPCTSTR lpCurrentDirectory,       // 子進程工作目錄 (NULL=繼承)
    LPSTARTUPINFO lpStartupInfo,      // 主視窗顯示/標準輸入輸出/標準錯誤重導向
    LPPROCESS_INFORMATION lpProcInfo  // 輸出: hProcess, hThread, dwProcessId, dwThreadId
);

關鍵參數深度解析

1. lpApplicationName vs lpCommandLine

  • 兩者至少一個非 NULL。
  • 最佳實踐: lpApplicationName = NULL,完整路徑與參數全放 lpCommandLine (如 L"C:\\App\\Child.exe --arg1 value"),系統自動解析第一個 token 為模組路徑,支援空格路徑 (需加雙引號)。

2. dwCreationFlags 常用值

3. lpEnvironment 環境塊

  • NULL:子進程繼承父進程環境變數 (複製一份)。
  • 自定義:指向 Key=Value\0Key2=Value2\0\0 格式的記憶體區塊 (雙 Null 結尾)。
  • 獲取當前環境:GetEnvironmentStrings() (需 FreeEnvironmentStrings)。

4. STARTUPINFO 標準輸入/輸出/錯誤重導向 (管道通訊核心)

STARTUPINFO si = { sizeof(si) };
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput  = hChildStdinRead;   // 父寫入 -> 子讀取
si.hStdOutput = hChildStdoutWrite; // 子寫入 -> 父讀取
si.hStdError  = hChildStdoutWrite; // 合併錯誤輸出
// 管道建立需: CreatePipe(&hRead, &hWrite, &sa, 0); sa.bInheritHandle = TRUE;

完整創建、等待、獲取退出碼範例

bool LaunchAndWait(const CString& cmdLine, DWORD& exitCode, DWORD timeoutMs = INFINITE) {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = {0};

    // 命令列需可修改緩衝區
    CString cmd = cmdLine; // 複本
    LPTSTR pCmd = cmd.GetBuffer();

    BOOL ok = CreateProcess(NULL, pCmd, NULL, NULL, FALSE,
                            CREATE_NO_WINDOW, // 或 CREATE_NEW_CONSOLE
                            NULL, NULL, &si, &pi);
    cmd.ReleaseBuffer();

    if (!ok) return false;

    // 關閉父進程不需要的句柄
    CloseHandle(pi.hThread); // 不需要執行緒句柄

    // 等待進程結束
    DWORD wait = WaitForSingleObject(pi.hProcess, timeoutMs);
    if (wait == WAIT_OBJECT_0) {
        GetExitCodeProcess(pi.hProcess, &exitCode);
    } else if (wait == WAIT_TIMEOUT) {
        // 可選: TerminateProcess(pi.hProcess, 1);
    }

    CloseHandle(pi.hProcess);
    return (wait == WAIT_OBJECT_0);
}

// 使用
DWORD code;
if (LaunchAndWait(_T("\"C:\\Program Files\\MyApp\\Worker.exe\" /task 123"), code, 30000)) {
    TRACE(_T("Child exited with code %lu\n"), code);
}

進程與執行緒的區別回顧

  • 進程:獨立地址空間、資源擁有者、開銷大、隔離性強 (一個崩潰不影響其他)。
  • 執行緒:共享進程地址空間/資源、開銷小、切換快、同步複雜 (鎖/死鎖)、一個崩潰導致全進程倒下。
  • 選擇原則: 需隔離 (不穩定模組、不同權限、不同用戶) 用進程;需高頻共享數據、緊密協作用執行緒。

常見錯誤與避坑

  1. lpCommandLine 指向常量字串字面值 → 崩潰 (系統嘗試修改)。必須用可寫緩衝區 (CString::GetBuffer/std::vector)。
  2. 路徑含空格未加雙引號 → 啟動錯誤檔案。格式:L"\"C:\\Program Files\\App.exe\" arg"。
  3. 忘記 CloseHandle(pi.hProcess) / pi.hThread → 核心物件洩漏,導致進程無法完全退出 (殭屍進程)。
  4. bInheritHandles=TRUE 但未在 SECURITY_ATTRIBUTES 設置 bInheritHandle=TRUE → 句柄實際不繼承。
  5. 等待無限制 INFINITE 導致父進程凍結 → 設置超時或另起執行緒等待。

掌握 CreateProcess 細節,是 Windows 系統級開發的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
旗標效果
CREATE_NEW_CONSOLE子進程擁有獨立主控台視窗
CREATE_NO_WINDOW無主控台 (GUI 程式適用)
DETACHED_PROCESS無主控台,且不繼承父主控台
CREATE_SUSPENDED主執行緒建立後暫停,需 ResumeThread 繼續 (注入/調試用)
CREATE_UNICODE_ENVIRONMENTlpEnvironment 為 Unicode 環境塊
DEBUG_PROCESS / DEBUG_ONLY_THIS_PROCESS父進程作為除錯器附加