CreateProcess函数原型如下:
BOOL CreateProcess( PCTSTR pszApplicationName, PTSTR pszCommandLine, PSECURITY_ATTRIBUTES psaProcess, PSECURITY_ATTRIBUTES psaThread, BOOL bInheritHandles, DWORD fdwCreate, PVOID pvEnvironment, PCTSTR pszCurDir, PSTARTUPINFO psiStartInfo, PPROCESS_INFORMATION ppiProcInfo);
一、参数 PCTSTR pszApplicationName 和 参数PTSTR pszCommandLine:
该参数类型为PTSTR,在函数运行过程中,CreateProcess函数会修改其值,
但是在CreateProcess返回前又会复原为原来传入时的值.
//所以如下调用可能会出错: STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; CreateProcess(NULL, TEXT("NOTEPAD"), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); //正确的调用应该是先将其传给一个变量,然后将该变量作为参数传入: STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; TCHAR szCommandLine[] = TEXT("NOTEPAD"); CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
如果pszApplicationName 值为NULL时,CreateProcess函数就会解析pszCommandLine参数,pszCommandLine参数需要包含一个进程创建的所有参数,如新进程的可执行文件名。如果程序没有后缀名,默认的后缀名是.exe。CreateProcess函数会按照如下五种顺序来搜寻对应的程序名:
- 主调进程.exe文件的所在目录。
- 主调进程的的当前目录。
- windows 系统目录,即GetSystemDirectory返回的System32子文件夹。
- windows目录。
- PATH环境变量中列出的目录。
如果如果pszApplicationName 值不为NULL时,你必须在pszApplicationName传入可执行文件名(包含后缀名)。并且没有指定可执行文件的路径,reateProcess函数假设可执行文件就在当前目录,如果没有找到,则函数直接返回FALSE,不会按照上面那五种目录进行查找。实例如下:
// Make sure that the path is in a read/write section of memory. TCHAR szPath[] = TEXT("WORDPAD README.TXT"); // Spawn the new process. CreateProcess(TEXT("C:\\WINDOWS\\SYSTEM32\\NOTEPAD.EXE"),szPath,...);
二、参数psaProcess, psaThread, 和 bInheritHandles
创建一个新进程时一个进程和一个基线程。由于两个都是Kernel Object,都需要有两个对应的PSECURITY_ATTRIBUTES的结构体。psaProcess 和 psaThread 分别指向这两个结构体。你可以通过设置这两个结构体的值来设置对应的子进程和基线程的安全属性,如果这两个值都为NULL时,则系统将赋予进程和基线程默认的安全描述符。父进程在以后再创建子进程时,通过把bInhertHandles参数设置为TRUE,就可以让新的子进程继承父进程所有
可继承的句柄(handle)。一个实例如下:
/************************************************************ Module name: Inherit.cpp Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre ************************************************************/ #include <Windows.h> #include <tchar.h> int WINAPI _tWinMain (HINSTANCE hInstanceExe, HINSTANCE, PTSTR pszCmdLine, int nCmdShow) { // Prepare a STARTUPINFO structure for spawning processes. STARTUPINFO si = { sizeof(si) }; SECURITY_ATTRIBUTES saProcess, saThread; PROCESS_INFORMATION piProcessB, piProcessC; TCHAR szPath[MAX_PATH]; // Prepare to spawn Process B from Process A. // The handle identifying the new process // object should be inheritable. saProcess.nLength = sizeof(saProcess); saProcess.lpSecurityDescriptor = NULL; saProcess.bInheritHandle = TRUE; // The handle identifying the new thread // object should NOT be inheritable. saThread.nLength = sizeof(saThread); saThread.lpSecurityDescriptor = NULL; saThread.bInheritHandle = FALSE; // Spawn Process B. _tcscpy_s(szPath, _countof(szPath), TEXT("ProcessB")); CreateProcess(NULL, szPath, &saProcess, &saThread, FALSE, 0, NULL, NULL, &si, &piProcessB); // The pi structure contains two handles // relative to Process A: // hProcess, which identifies Process B's process // object and is inheritable; and hThread, which identifies // Process B's primary thread object and is NOT inheritable. // Prepare to spawn Process C from Process A. // Since NULL is passed for the psaProcess and psaThread // parameters, the handles to Process C's process and // primary thread objects default to "noninheritable." // If Process A were to spawn another process, this new // process would NOT inherit handles to Process C's process // and thread objects. // Because TRUE is passed for the bInheritHandles parameter, // Process C will inherit the handle that identifies Process // B's process object but will not inherit a handle to // Process B's primary thread object. _tcscpy_s(szPath, _countof(szPath), TEXT("ProcessC")); CreateProcess(NULL, szPath, NULL, NULL, TRUE, 0, NULL, NULL, &si, &piProcessC); return(0); }
三、参数 fdwCreate
fdwCreate指定一些如何创建进程的标识符。同时也可以指定子进程的优先级类型。不过一般的话,都是直接将该值置为0.
四、参数 pvEnvironment
pvEnvironment指向子进程将要用到的环境变量的内存地址块。如果没有的话,就可以直接置为NULL。
五、参数 pszCurDir
pszCurDir参数可以让CreateProcess函数设置子进程的当前驱动器和目录。如果传入时是NULL,则子进程的当前驱动器和目录和父进程一样。如果传入时不为NULL,则必须是一个以'\0'结束的合法的当前驱动器和目录。
六、参数 psiStartInfo
psiStartInfo是一个指向 STARTUPINFO或 STARTUPINFOEX结构体的指针, 一般都不用怎么设置,一般只要这样初始化第一个值就可以了。如:STARTUPINFO si = { sizeof(si) };
七、参数 ppiProcInfo
ppiProcInfo 指向一个 PROCESS_INFORMATION 结构体,CreateProcess函数会对它进行初始化。
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
正如上面提到的,父进程创建子进程时,会创建一个子进程对象(process kernel object)和一个基线程对象(primary thread kernel object)。hProcess 和 hThread 分别记录子进程对象的句柄和父进程对象的句柄。dwProcessId 和 dwThreadId 分别记录这个两个对象的ID号。特别需要注意的是:当CreateProcess函数创建一个个子进程对象(process kernel object)和一个基线程对象(primary thread kernel object),系统就将这两个内核对象的初始引用值置为1。子进程会再打开这两个对象,此时它们的引用值就增加为 2 。也就是说如果要释放这两内核对象,则必须在父子进程中都要执行对应的CloseHandle函数。实例如下:
PROCESS_INFORMATION pi; DWORD dwExitCode; // Spawn the child process. BOOL fSuccess = CreateProcess(..., &pi); if (fSuccess) { // Close the thread handle as soon as it is no longer needed! CloseHandle(pi.hThread); // Suspend our execution until the child has terminated. WaitForSingleObject(pi.hProcess, INFINITE); // The child process terminated; get its exit code. GetExitCodeProcess(pi.hProcess, &dwExitCode); // Close the process handle as soon as it is no longer needed. CloseHandle(pi.hProcess); }