进程与多线程
作者:Ackarlix
一、进程的创建
一般将创建进程的称为父进程,被创建的进程称为子进程。系统在创建新的进程时会为新进程指定一个STARTUPINFO类型的变量,这个结构包含了父进程传递给子进程的一些显示信息。对界面应用程序来说,这些信息将影响进程中主线程的窗口显示;对控制台应用程序来说,将影响这个控制台程序的窗口。
STARTUPINFO
STARTUPINFO结构定义如下:
typedef struct _STARTUPINFO {
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
参数解析:
DWORD cb; //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它
//可用作版本控制手段。应用程序须将cb初始为sizeof(STARTUPINF/O)
PSTR lpReserved; //保留。必须初始化为NULL
PSTR lpDesktop; //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与 //指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面
//并使用为新进程指定的名字。如果lpDesktop是NULL
//(这是最常见的情况),那么该进程将与当前桌面相关联
PSTR lpTitle; //用于设定控制台窗口的名称。如lpTitle是NULL,则可执行文件的名字将
//用作窗口名
DWORD dwX; //用于设定应用程序窗口在屏幕上应该放置的位置的x 和y 坐标(以像素为
//单位)。
DWORD dwY; //只有当子进程用CW_USEDEFAULT作为CreateWindow的x参数创建
//它的第一个重叠窗口时,才使用这两个坐标。若是创建控制台窗口的应用
//程序,这些成员用于指明控制台窗口的左上角
DWORD dwXSize; //用于设定应用程序窗口的宽度和长度(以像素为单位)只有dwYsize
DWORD dwYSize; //当子进程将CW_USEDEFAULT用作Create Window的nWidth参数来
//建它的第一个重叠窗口时,才使用这些值。若是创建控制台窗口的应用程
//序,这些成员将用于指明控制台窗口的宽度
DWORD dwXCountChars; //用于设定子应用程序的控制台窗口的宽度和高度(以字符为单位)
DWORD dwYCountChars;
DWORD dwFillAttribute; //用于设定子应用程序的控制台窗口使用的文本和背景颜色
DWORD dwFlags; //请参见下一段和表4-7的说明
表4-7 dwFlags 使用标志及含义
标志 含义
STARTF_USESIZE // 使用dwXSize和dwYSize成员
STARTF_USESHOWWINDOW //使用wShowWindow成员
STARTF_USEPOSITION //使用dwX和dwY成员
STARTF_USECOUNTCHARS //使用dwXCountChars和dwYCountChars 成员
STARTF_USEFILLATTRIBUTE //使用dwFillAttribute成员
STARTF_USESTDHANDLES //使用hStdInput、hStdOutput和hStdError成员
STARTF_RUN_FULLSCREEN //强制x86计算机上运行的控制台应用程序以全屏方式启动运行
WORD wShowWindow; //用于设定如果子应用程序初次调用的ShowWindow将
//SW_SHOWDEFAULT作为nCmdShow参数传递,该应用程序的第一个
//重叠窗口应该如何出现。本成员可以是通常用于ShowWindow函数的任
//何一个SW_*标识符
WORD cbReserved2; //保留。必须被初始化为0
PBYTE lpReserved2; //保留。必须被初始化为NULL
HANDLE hStdInput; //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,
//hStdInput用标识键盘缓存,hStdOutput和hStdError用于标识控制台窗
//口的缓存
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
一个进程可以用GetStartupInfo函数来取得父进程创建自己所用的STARTUPINFO结构。定义一个STARTUPINFO结构对象以后,总要在使用对象之前将对象的cb成员初始化为STARTUPINFO结构大小。
如:
STARTUPINFO si = {sizeof(si)};
::GetStartupInfo(&si);
CreateProcess函数
CreateProcess函数创建一个新的进程和该进程的主线程。新的进程在父进程的安全上下文中运行指定的可执行文件。
原型:
BOOL CreateProcess
(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
参数解析:
lpApplicationName:指向一个NULL结尾的、用来指定可执行模块的字符串。 这个字符串可以使可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。 这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数的最前面并由空格符与后面的字符分开。 这个被指定的模块可以是一个Win32应用程序。如果适当的子系统在当前计算机上可用的话,它也可以是其他类型的模块(如MS-DOS 或 OS/2)。
lpCommandLine:指向一个NULL结尾的、用来指定要运行的命令行。 这个参数可以为空,那么函数将使用参数指定的字符串当作要运行的程序的命令行。 如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。 如果lpApplicationName参数为空,那么这个字符串中的第一个被空格分隔的要素指定可执行模块名。如果文件名不包含扩展名,那么.exe将被假定为默认的扩展名。如果文件名以一个点(.)结尾且没有扩展名,或文件名中包含路径,.exe将不会被加到后面。如果文件名中不包含路径,Windows将按照如下顺序寻找这个可执行文件:
1. 当前应用程序的目录。
2. 父进程的目录。
3. Windows 95:Windows系统目录,可以使用GetSystemDirectory函数获得。 Windows NT:32位Windows系统目录。可以使用GetSystemDirectory函数获得,目录名是SYSTEM32。
4. 在Windows NT中:16位Windows系统目录。不可以使用Win32函数获得这个目录,但是它会被搜索,目录名是SYSTEM。
5. Windows目录。可以使用GetWindowsDirectory函数获得这个目录。
6. 列在PATH环境变量中的目录。
如果被创建的进程是一个以MS-DOS或16位Windows为基础的应用程序,lpCommandLine参数应该是一个以可执行文件的文件名作为第一个要素的绝对路径,因为这样做可以使32位Windows程序工作的很好,这样设置lpCommandLine参数是最强壮的。
lpProcessAttributes