事实上,手动建立进程是属于 winapi,而不是由 MFC 的封装。
通常,我们在想要打开其他应用的时候,就需要在程序中用到 CreateProcess 函数了。

CreateProcess

这个函数会建立一个新的进程,及其主线程。新进程运行在调用此方法的安全上下文中。

如果当前登录用户是 A,而调用进程是以 B 的身份运行的,那么新的进程会使用 A 进行运行,而不使用 B用户,也就是说,不会继承调用进程的身份信息。

如果想要让新进程以 B 身份运行的话,那么考虑使用 CreateProcessAsUser()CreateProcessWithLogonW()

基本语法

BOOL CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
  • lpApplicationName 要执行的模块名称。可以是完整路径,也可以是一个相对路径。如果是相对路径的话就会在当前目录下进行查找,其不会使用系统路径进行查找。这个名称必须包扩扩展名。此参数也可以是 NULL,那么其将将 lpCommandLine 参数的第 1 段当作模块名称。
  • lpCommandLine 命令行参数。如果我们 lpApplicationName 为空的情况下,我们可以用 “calc file.txt” 这样的形式来指定这个参数。
  • lpProcessAttributes 进程属性。一个指向 SECURITY_ATTRIBUTES 数据结构的指针,用来决定函数返回的新进程的 Handle 能否被子进程继承。如果设置为 NULL,那么是不可继承的。
  • lpThreadAttributes 同上,指定线程属性。
  • bInheritHandles 如果此参数为 TRUE,在调用进程中的所有可继承的 Handle 都会被新进程继承。
  • dwCreationFlags 建立标志。
  • lpEnvironment 指新进程的运行环境。如果指定为 NULL,则和调用进程一致。
  • lpCurrentDirectory 工作目录。完整路径。如果为 NULL,则和调用进程一致。
  • lpStartupInfo 指向 STARTUPINFO[EX]的结构。
  • lpProcessInformation 指向 PROCESS_INFORMATION。

需要注意的是, lpCommandLine 的类型是 LPSTR 表示这是一个可变的,必须用变量的形式来传递不能用常量。不然将会出现异常。
这个建立进程,真心的比 linux的,fork-execute 麻烦多了。

返回值

如果建立成功,返回值是非0的。如果返回值为0,那么可以用 GetLastError() 来获取错误信息。

备注

新进程会被指定一个标识符。这个标识符在进程存在期间都可用。可以用来标识此进程,或者作为 OpenProcess() 参数来打开一个对此进程引用的 Handle。

初始化的线程也会被赋予标识符。同样可以作为参数传递给 OpenThread()

调用线程可以用 WaitForInputIdle() 函数来等待,直到新的进程初始化完毕,用户已经没有输入。这在父子进程间进行同步是非常有用的,因为 CreateProcess() 不会等待子进程的初始化完毕。具体而言,调用进程可以用 WaitForInputIdle() 来等待直到已经有一个窗口附到了子进程上。

首选方式是使用 ExitProcess() 来结束进程,这个方式会通知将所有的 DLL 都给关掉。

实例

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );

if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return;
}

// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}

// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );

// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}

成功建立进程后会返回包含了 进程和线程 Handle 的 PROCESS_INFORMATION 结构。这两个 Handle 及时我们指定了安全限制的情况都具有完全的访问权限,如果我们不需要的话,就需要关闭这两个 Handle。