BOOL CreateProcess(
LPCSTR lpApplicationName, // 模塊名(可為NULL)
LPSTR lpCommandLine, // 命令行(可修改緩衝區)
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 進程安全屬性
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 主線程安全屬性
BOOL bInheritHandles, // 句柄繼承
DWORD dwCreationFlags, // 創建標誌
LPVOID lpEnvironment, // 環境塊
LPCSTR lpCurrentDirectory, // 工作目錄
LPSTARTUPINFO lpStartupInfo, // 啟動信息
LPPROCESS_INFORMATION lpProcessInformation // 返回信息
);
lpCommandLine 僅作為參數傳遞(argv[1...]),第一個參數通常重複程序名lpCommandLine 第一個 token 解析為模塊名(支持帶空格路徑需加引號)lpApplicationName 為完整路徑,lpCommandLine 為完整命令行(含程序名),避免路徑解析歧義SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; // 允許繼承
CreateProcess(..., &sa, &sa, TRUE, ...); // bInheritHandles=TRUE
子進程將繼承父進程所有可繼承句柄(文件、管道、Socket等)。
| 標誌 | 用途 |
|---|---|
| CREATE_NEW_CONSOLE | 分配新控制台窗口 |
| CREATE_NO_WINDOW | 無窗口(GUI程序隱藏控制台) |
| DETACHED_PROCESS | 無控制台、無窗口(服務型) |
| CREATE_SUSPENDED | 主線程掛起創建,需 ResumeThread |
| CREATE_UNICODE_ENVIRONMENT | 環境塊為 Unicode |
| DEBUG_PROCESS | 以調試器身份創建 |
| EXTENDED_STARTUPINFO_PRESENT | 使用 STARTUPINFOEX |
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE; // 隱藏窗口
si.hStdInput = hChildStdinRead; // 重定向標準輸入
si.hStdOutput = hChildStdoutWrite; // 重定向標準輸出
si.hStdError = hChildStderrWrite; // 重定向標準錯誤
bool LaunchAndWait(const char* cmdLine, DWORD timeoutMs = INFINITE) {
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
// 安全屬性:不繼承句柄
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
BOOL success = CreateProcess(
NULL, // 模塊名從命令行解析
(LPSTR)cmdLine, // 命令行(需可修改緩衝區!)
&sa, &sa, // 進程/線程安全屬性
FALSE, // 不繼承句柄
CREATE_NO_WINDOW, // 無控制台窗口
NULL, // 繼承環境
NULL, // 繼承工作目錄
&si, &pi // 輸入/輸出
);
if (!success) return false;
// 關閉不需要的句柄
CloseHandle(pi.hThread);
// 等待進程退出
DWORD waitResult = WaitForSingleObject(pi.hProcess, timeoutMs);
DWORD exitCode = 0;
GetExitCodeProcess(pi.hProcess, &exitCode);
CloseHandle(pi.hProcess);
return waitResult == WAIT_OBJECT_0;
}
// 1. 創建管道
HANDLE hChildStdinRead, hChildStdinWrite;
HANDLE hChildStdoutRead, hChildStdoutWrite;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
CreatePipe(&hChildStdinRead, &hChildStdinWrite, &sa, 0);
CreatePipe(&hChildStdoutRead, &hChildStdoutWrite, &sa, 0);
// 2. 設置父進程不繼承寫端/讀端
SetHandleInformation(hChildStdinWrite, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(hChildStdoutRead, HANDLE_FLAG_INHERIT, 0);
// 3. 配置 STARTUPINFO
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdInput = hChildStdinRead;
si.hStdOutput = hChildStdoutWrite;
si.hStdError = hChildStdoutWrite;
si.wShowWindow = SW_HIDE;
// 4. 創建進程
CreateProcess(NULL, cmdLine, &sa, &sa, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
// 5. 父進程通信
WriteFile(hChildStdinWrite, inputData, len, &written, NULL);
ReadFile(hChildStdoutRead, buffer, size, &read, NULL);
lpCommandLine 可能被修改,必須傳遞可寫緩衝區(strdup 或 std::vector)"C:\\Program Files\\App\\app.exe" arg1 arg2CreateProcess 成功時必須關閉 pi.hProcess 和 pi.hThreadlpCurrentDirectory=NULL 繼承父進程目錄,相對路徑解析基於此目錄lpEnvironment 為 Key=Value\0Key=Value\0\0 雙重空終止,Unicode 標誌下為寬字符CREATE_SUSPENDED + QueueUserAPC 可實現代碼注入,防護需監控此標誌組合public static class ProcessLauncher {
public static ProcessResult Run(string fileName, string arguments,
string workingDir = null, int timeoutMs = -1,
Dictionary envVars = null) {
var psi = new ProcessStartInfo(fileName, arguments) {
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
WorkingDirectory = workingDir ?? Environment.CurrentDirectory
};
if (envVars != null) {
foreach (var kv in envVars) psi.EnvironmentVariables[kv.Key] = kv.Value;
}
using (var proc = Process.Start(psi)) {
var output = proc.StandardOutput.ReadToEnd();
var error = proc.StandardError.ReadToEnd();
bool exited = proc.WaitForExit(timeoutMs);
return new ProcessResult {
ExitCode = proc.ExitCode,
Output = output,
Error = error,
TimedOut = !exited
};
}
}
}
掌握 CreateProcess 的每個參數含義與組合邏輯,是 Windows 系統編程、沙箱構建、自動化測試框架開發的核心技能。