一般将进程定义为一个正在运行的程序的一个实例,由以下两部分构成。
进程是惰性的,进程要做任何事,都必须让一个线程在它的上下文中运行,该线程负责执行进程地址空间包含的代码,一个进程可以有多个线程,所有的线程都在进程的地址空间中“同时”执行代码。
- DWORD GetCurrentDirectory(
- [in] DWORD nBufferLength,
- [out] LPTSTR lpBuffer
- );
参数1:当前目录字符串的缓冲区长度,缓冲区长度必须包含终止空字符的空间。
参数2:指向接收当前目录字符串的缓冲区的指针。这个以空结尾的字符串指定到当前目录的绝对路径。
返回值:如果函数成功,返回值指定写入缓冲区的字符数,不包括终止的'\0'。
一个线程调用CreateProcess时,系统将创建一个进程内核对象,其初始化计数为1,进程内核对象对象不是进程本身,而是操作系统用来管理这个进程的一个小型数据结构。然后,系统为新进程创建一个虚拟地址空间,并将可执行文件和必要的DLL的代码及数据加载到进程的地址空间。
接着操作系统为新进程的主线程创建一个线程内核对象(其使用计数为1)。和进程内核对象一样,线程内核对象也是一个小型的数据结构,操作系统用它来管理这个线程。这个主线程一开始就会执行C/C++运行时的启动例程,它是由链接器设为应用程序入口的,最终会调用应用程序WinMain,wWinMain函数。如果系统成功创建了新进程和主线程,返回TRUE。
- BOOL CreateProcessW(
- [in, optional] LPCWSTR lpApplicationName,
- [in, out, optional] LPWSTR lpCommandLine,
- [in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
- [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
- [in] BOOL bInheritHandles,
- [in] DWORD dwCreationFlags,
- [in, optional] LPVOID lpEnvironment,
- [in, optional] LPCWSTR lpCurrentDirectory,
- [in] LPSTARTUPINFOW lpStartupInfo,
- [out] LPPROCESS_INFORMATION lpProcessInformation
- );
lpApplicationName:可执行文件的名称。
- (1)主调进程.exe文件所在的目录
-
- (2)主调进程的当前目录
-
- (3)windows系统目录,即GetSystemDirectory返回的System32子文件夹
-
- (4)windows目录
-
- (5)PATH环境变量中列出的目录
lpCommandLine:传给新进程的命令行字符串,这个参数类型是LPWSTR,是一个非常量的字符串,CreateProcess实际上会修改我们传给它的命令行字符串。当然在它返回前,它会把这个字符串还原,所以这样的代码是错误的:因为C/C++编译器把“NOTEPAD”字符串放在只读内存中。
- 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) ;
lpProcessAttributes:指向SECURITY_ATTRIBUTES结构的指针,该结构决定新进程对象的返回句柄是否可以被子进程继承。如果lpProcessAttributes为NULL,句柄不能被继承。
lpThreadAttributes:指向SECURITY_ATTRIBUTES结构的指针,该结构决定新线程对象的返回句柄是否可以被子进程继承。如果lpThreadAttributes为NULL,句柄不能被继承。
bInheritHandles:如果此参数为TRUE,则调用进程中的每个可继承句柄将被新进程继承。如果参数为FALSE,则不继承句柄。
dwCreationFlags:控制优先级类和进程创建的标志。
lpEnvironment:指向新进程的环境块的指针。如果该参数为NULL,则新进程使用调用进程的环境。
lpCurrentDirectory:进程当前目录的完整路径。如果此参数为NULL,则新进程将具有与调用进程相同的当前驱动器和目录。
lpStartupInfo:指向STARTUPINFO或STARTUPINFOEX结构体的指针。
lpProcessInformation:指向PROCESS_INFORMATION结构的指针,该结构接收关于新进程的标识信息。
示例:创建一个子进程。
- #include
- #include
- #include
-
- 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 );
- }
有以下4中方式终止:
4.1使用ExitProcess函数
会导致进程或线程直接终止运行,不能正常执行清理工作,示例如下:
-
- class Test {
- public:
- Test() { printf("Construct \r\n"); }
- ~Test() { printf("Destruct \r\n"); }
- };
-
- Test g_test;
-
- int main()
- {
- Test test;
- ExitProcess(0);
- }
结果如下图所示:只构造,不析构。

4.2使用TerminateProcess函数
此函数与ExitProcess有一个明显的区别:任何线程都可以调用TerminalProcess来终止另一个进程或者它自己的进程。
只有在无法通过其他方法来强制进程退出时,才使用TerminateProcess。
虽然进程没有机会执行自己的清理工作,但操作系统会在进程终止之后彻底进行清理,确保不会泄露任何操作系统资源。这意味着使用的所有内存都会被释放,所有打开的文件都会被关闭,所有的内核对象的使用计数都将递减等等。
TerminateProcess是异步的;它启动终止并立即返回。如果需要确定进程已经终止,可以调用带有进程句柄的WaitForSingleObject函数。