Win32 - 创建进程
1. 核心函数:CreateProcess
Windows 中创建进程的 API 是 CreateProcess。它会创建一个新进程和它的主线程,并加载指定的可执行文件。
BOOL CreateProcess(
LPCWSTR lpApplicationName, // 可执行文件路径
LPWSTR lpCommandLine, // 命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全属性(通常为NULL)
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性(通常为NULL)
BOOL bInheritHandles, // 句柄是否可继承
DWORD dwCreationFlags, // 创建标志(如 CREATE_NEW_CONSOLE)
LPVOID lpEnvironment, // 环境变量(NULL=继承父进程)
LPCWSTR lpCurrentDirectory, // 工作目录(NULL=同父进程)
LPSTARTUPINFOW lpStartupInfo, // 启动信息(窗口样式等)
LPPROCESS_INFORMATION lpProcessInformation // 返回进程/线程句柄和ID
);
重点:最后一个参数 lpProcessInformation 会返回新进程的句柄和 ID,之后可以用 WaitForSingleObject 等待进程结束,用 CloseHandle 关闭句柄。
2. 最简单的示例:启动一个记事本
#include <windows.h>
#include <stdio.h>
int main()
{
STARTUPINFOW si = { sizeof(si) }; // 必须初始化大小
PROCESS_INFORMATION pi = { 0 }; // 用于接收进程信息
// 创建进程启动记事本
BOOL success = CreateProcessW(
L"C:\\Windows\\System32\\notepad.exe", // 应用程序路径
NULL, // 命令行参数(无额外参数)
NULL, NULL, // 安全属性(默认)
FALSE, // 句柄不继承
0, // 创建标志(普通)
NULL, // 使用父进程环境变量
NULL, // 使用父进程工作目录
&si, // 启动信息
&pi // 进程信息输出
);
if (!success)
{
printf("CreateProcess failed, error code: %d\n", GetLastError());
return 1;
}
printf("新进程 PID = %d\n", pi.dwProcessId);
// 等待新进程结束(无限等待)
WaitForSingleObject(pi.hProcess, INFINITE);
printf("记事本已关闭,继续执行。\n");
// 关闭句柄,避免资源泄露
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
编译运行:
用 cl /EHsc CreateProcessDemo.cpp 编译,然后执行。会打开记事本,等你关闭记事本后,控制台才会打印结束信息。
3. 带命令行参数的示例:启动自己的程序
假设当前目录下有一个 SemaphoreSignal.exe 需要启动(不需要传参数时可直接在 lpCommandLine 中写 NULL),如果需要传参数,则必须使用可写的缓冲区,且 lpApplicationName 可以设为 NULL。
#include <windows.h>
#include <stdio.h>
int main()
{
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
// 命令行字符串(必须可修改,所以用数组)
wchar_t cmdLine[] = L"SemaphoreSignal.exe";
BOOL success = CreateProcessW(
NULL, // 使用命令行中的可执行文件名称
cmdLine, // 命令行(可包含参数,例如 L"SemaphoreSignal.exe arg1 arg2")
NULL, NULL,
FALSE,
0,
NULL, NULL,
&si,
&pi
);
if (!success)
{
printf("CreateProcess failed, error: %d\n", GetLastError());
return 1;
}
// 可选:等待子进程结束
WaitForSingleObject(pi.hProcess, INFINITE);
printf("子进程已退出。\n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
注意:
-
lpCommandLine必须是一个可写的缓冲区,不能是字符串常量(如L"..."),因为CreateProcess可能会修改它。 -
如果可执行文件不在当前目录或系统 PATH 中,应给出完整路径,或在
lpApplicationName中指定完整路径。
4. 常用创建标志 (dwCreationFlags)
| 标志 | 作用 |
|---|---|
CREATE_NEW_CONSOLE |
新进程创建一个新控制台窗口(而非继承父进程的控制台) |
CREATE_NO_WINDOW |
不创建窗口(用于后台进程) |
DEBUG_PROCESS |
调试新进程 |
CREATE_SUSPENDED |
主线程挂起,需手动调用 ResumeThread |
示例:启动一个带新控制台窗口的程序:
CreateProcessW(..., CREATE_NEW_CONSOLE, ...);
5. 获取进程退出码
可以用 GetExitCodeProcess 获得进程的返回值(即 main 或 WinMain 的返回值):
DWORD exitCode;
if (GetExitCodeProcess(pi.hProcess, &exitCode))
printf("子进程退出码: %d\n", exitCode);
6. 注意事项
-
必须关闭句柄:
pi.hProcess和pi.hThread即使进程已结束,也必须调用CloseHandle释放内核对象引用计数。 -
缓冲区生命周期:
lpCommandLine指向的内存必须保证在CreateProcess调用期间有效,且不要被提前释放。 -
路径空格:如果可执行文件路径包含空格,必须用双引号括起来,并且要将整个路径放在
lpApplicationName中,或者使用lpCommandLine时也加上引号。CreateProcessW(L"\"C:\\Program Files\\MyApp\\app.exe\"", NULL, ...); -
继承句柄:若
bInheritHandles = TRUE,子进程会继承父进程的可继承的句柄(如文件映射、信号量等),使用时需小心,避免意外共享。
7. 完整示例:启动 SemaphoreSignal.exe 并等待
结合之前信号量的例子,你可以在 SemaphoreWait.exe 中创建一个子进程来运行 SemaphoreSignal.exe,自动释放信号量。
// 在 SemaphoreWait.cpp 中,获得信号量后可以创建子进程释放它
// 仅作演示,实际业务中不这么用
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
wchar_t cmd[] = L"SemaphoreSignal.exe";
CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE); // 等待信号量释放程序执行完毕
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

浙公网安备 33010602011771号