Windows 是以对象的方式来管理进程的,它由 Win32 子系统来创建和维护,并且可以由此进程的句柄来进行管理。进程的创建一般是在一个进程的线程中调用函数CreateProcess( )来创建的,这个进程可以和原进程共享资源(例如句柄和变量),而且在Windows 中,这两个进程不存在的父子关系,即使原进程终止后,这个新进程仍然可以继续执行。
(1) SECURITY_ATTRIBUTES 结构
该结构存放一个对象的安全描述符并指定是否继承返回的句柄。SECURITY_
ATTRIBUTES 结构定义如下。
typedef struct_SECURITY_ATTRIBUTES{
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
}SECURITY_ATTRIBUTES
其中成员含义如下。
① nLength:指定该结构大小。
② lpSecurityDescriptor:指向一个对象的安全描述符,该安全描述符控制对象的共享。如果该成员置为 NULaL,则该对象使用调用进程的默认安全描述符。
③ bInheritHandle:指定新进程被创建时是否继承返回的句柄。若该成员置为 TRUE,则新进程继承该句柄。
(2) 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; Visual C++ 程序设计教程与上机指导
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserverd2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
}STARTUPINFO,*LPSTARTUPINFO;
其中成员含义如下。
① cb:指定该结构大小。
② lpReserved:保留,置为 NULL。
③ lpDesktop:指定一个字符串,包括该进程的桌面名或窗口位置名。
④ lpTitle:指定控制台进程创建的新控制台窗口标题。
⑤ dwX,dwY:指定新窗口左上角的 x 和 y 偏移量(以像素为单位)。如果 dwFlags 成员未指定 STARTF_USEPOSITION 标志,则忽略这两项。
⑥ dwXSize,dwYSize:指定新窗口的宽度和高度。如果 dwFlags 成员未指定STARTF_USESIZE 标志,则忽略这两个成员。
⑦ dwXCountChars,dwYCountChars:指定新控制台窗口的屏幕缓冲区的宽度和高度。如果 dwFlags 成员未指定 STARTF_USECOUNTCHARS 标志,则忽略这两成员。
⑧ dwFillAttribute:指定新控制台窗口的初始文字和背景颜色。如果 dwFlags 成员未指定 STARTF_USEFILLATTRIBUTE 标志,则忽略该成员。
⑨ dwFlags:创建窗口标志。
⑩ wShowWindow :新窗口的显示状态。如果 dwFlags 成员未指定 STARTF_ USESHOWWINDOWW 标志,则忽略该成员。
11. cbReserved2:保留,必须置为 0。
12. lpReserved2:保留,必须置为 NULL。
13 hStdInput:指定一个句柄,该句柄用作进程的标准输入句柄。如果dwFlags 成员未指定 STARTF_USESTDHANDLES 标志,则忽略该成员。
14 hStdOutput:指定一个句柄,该句柄用作进程的标准输出句柄。如果dwFlags 成员未指定 STARTF_USESTDHANDLES,则忽略该成员。
15 hStdError:指定一个句柄,该句柄用作进程的标准错误句柄。如果dwFlags 成员未指定 STARTF_USESTDHANDLES,则忽略该成员。
(3) PROCESS_INFORMATION 结构
该结构返回有关新进程及其主线程的信息。其结构定义如下。
typedef struct_PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
}PROCESS_INFORMATION;
其中成员含义如下。
① hProcess:返回新进程的句柄。
② hThread:返回主线程的句柄。
③ dwProcessId:返回一个全局进程标识符。该标识符用于标识一个进程。从进程被创建到终止,该值始终有效。
④ dwThreadId:返回一个全局线程标识符。该标识符用于标识一个线程。从线程被创建到终止,该值始终有效。
可以使用 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
);
其中参数含义如下。
(1) lpApplicationName:指定要执行的应用程序的名字,该名字可以是全路径名。如果该参数为 NULL,则程序名必须是 lpszCommandLine 指向的字符串的第一个标识符。该参通常置为 NULL,而将程序名和参数放在 lpszCommandLine 指定的字符串中。
(2) lpCommandLine:是一个以 NULL 结尾的字符串的指针,它指向命令行参数。参数lpApplicationName 和 lpszCommandLine 不允许同时空,否则系统找不见新进程所对应的可
执行程序的文件名。
(3) lpProcessAttributes 和lpThreadAttributes:它们指向SECURITY_ATTRIBUTES 结构,分别用来确定待创建的进程和待创建进程的主线程的安全属性。如果使用默认安全属性,则该值为 NULL。
(4) bInheritHandles:用来确定新建的进程能否继承产生它的进程的句柄。若它的值为TRUE,则这个进程和线程所建立的句柄都可以被这个进程所建立的新进程所继承,即继承的句柄和原来的句柄有相同的值和存取权限。
(5) dwCreationFlags:该参数决定新进程产生的方式,它可以用逻辑或(|)的方式把下列值结合起来。
① CREATE_NEW_CONSOLE:为新进程建立一个新的控制台窗口。
② DETACHED_PROCESS:在默认情况下,新进程使用的是父进程的控制台窗口
③ CREATE_NEW_PROCESS_GROUP:这个新进程将是一个新进程组的根,进程组Visual C++ 程序设计教程与上机指导 包括该进程的所有子进程。
④ CREATE_SUSPENDED:新进程的主线程被创建在挂起状态,直到 Resume_Thread函数被调用后才运行。
⑤ DEBUG_PROCESS:如果设置该标志,调用该进程被当作调试者,新进程准备接收调试。系统把在进程被调试时所发生的调试事件通知给父进程。还有其他的值,可以在使用时参阅 MSDN 来学习。
(6) lpEnvironment:指向一个用于新进程的环境块。如果该参数为 NULL,则新进程继承调用进程的环境。
(7) lpCurrentDirectory:指向新进程的当前驱动器和目录的字符串。如果该参数为NULL,则使用调用进程的当前驱动器和目录。
(8) lpStartupInfo:指向一个 STARTUPINFO 结构,用户说明如何显示新进程的主窗口。
(9) lpProcessInformation:指向一个 PROCESS_INFORMATION 结构,用于接收有关新进程的标识信息。
函数 CreateProcess( )调用成功,返回值为 TRUE,否则为 FALSE。
进程被创建之后,就要对其进行管理,比如改变进程的优先级。而要管理进程,首先要取得这个进程的句柄或进程 ID。
函数 GetCurrentProcess 可以取得当前进程的句柄,其原型为:
HANDLE GetCurrentProcess(VOID)
这个函数返回一个指向当前进程的句柄,但这是一个伪句柄,即仅仅只能打开此进程对象,增加此对象的引用计数,这个伪句柄只能在当前进程中使用,而不能在其他进程中利用此句柄对这个进程进行操作。若在别的进程中对当前这个进程进行操作,可调用函数DuplicateHandle( )把这个伪句柄转换成一个真正的句柄。
函数 DWORD GetCurrentProcessID(VOID)可以取得当前进程的 ID,有一些 API 函数需要用到进程 ID。
Windows 支持 4 种不同的优先级:实时(Realtime)、高(High)、变通(Normal)和空闲(Idle),默认情况下进程的优先级为普通优先级。
在程序中可以使用相应的参数来设置进程的优先级,它们是:HIGH_PRIORITY_ CLASS( 高) ,IDLE_PRIORITY_CLASS( 空闲) ,NORMAL_PRIORITY_CLASS( 普通) ,
REALTIME_PRIORITY_CLASS(实时)。
一般进程的优先级默认为普通级,除非这个进程的父进程的优先级为空闲。进程优先级的设置很重要,对于高优先级,这个进程的线程将占据几乎所有的 CPU 时间。而对于 一
个空闲优先级的进程,其线程只有当 CPU 空闲时才开始执行,例如屏幕保护程序的优先级就为空闲的优先级,若用户闲着,则会启动这个屏幕保护程序。对于实时优先级进程,一般不作设置,因为在这种情况下,其他进程都不会执行,如果这个进程不结束,其结果和
死机一样。
CreateProcess( )函数允许父进程指定其子进程的优先级类别。在运行过程中可使用SetPriorityClass( )函数动态改变进程的优先级。另外可使用 GetPriorityClass( )获取进程的优
先级。如使用 DWORD m_pri=GetPriorityClass(GetCurrentProcess( )),可取得当前进程的优先级。
父进程可以使用 ExitProcess( )函数或 TerminateProcess( )函数终止子进程的运行。这两者之间的区别是:ExitProcess 函数将通知所有附属 DLL 终止并保证进程的全部线程都终止,而且只能终止当前进程;而 TerminateProcess 函数在终止进程时,并不通知所属 DLL,除非不得已,不要使用它来终止进程,因为它会导致其附属的 DLL 程序不能完成一些正常的数据刷新工作,该函数不仅能终止当前进程,还能终止其他的进程。
值得注意的是,终止一个进程并不会引起子进程的终止,而只是该进程及其所有线程的终止。
ExitProcess( )函数原型为:
void ExitProcess(UNIT uExitCode)
其中 uExitCode 为进程码。
TerminateProcess( )函数原型为:
BOOL TerminateProcess(HANDLE hProcess,UNIT uExitCode)
其中,参数 hProcess 标识要终止的进程,uExitCode 为进程的退出码。
应用程序可以使用 GetExitCodeProcess 返回进程的终止状态。如果进程还在运行,则终止状态为 STILL_ACTIVE。如果进程终止,则终止状态为进程退出码。
添加一个“运行”按钮,一个“浏览”按钮,一个文本框控件,m_strFileName为Edit控件映射。
浏览
void C多进程Dlg::OnBnClickedBrowse() { CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, _T("程序文件 |*.exe;*.com;*.bat| 所有文件 (*.*)|*.*||")); if (IDOK == dlg.DoModal()) { m_strFileName = dlg.GetPathName(); UpdateData(FALSE); } }
运行
void C多进程Dlg::OnBnClickedRun() { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; // 设置进程窗口信息结构 STARTUPINFO StartupInfo.cb=sizeof(STARTUPINFO); StartupInfo.lpReserved=NULL; StartupInfo.lpDesktop=NULL; StartupInfo.lpTitle=NULL; StartupInfo.dwFlags=STARTF_USESHOWWINDOW; StartupInfo.cbReserved2=0; StartupInfo.lpReserved2=NULL; StartupInfo.wShowWindow=SW_SHOWNORMAL; // 正常尺寸显示窗口 TCHAR filename[255]; _stprintf(filename,_T("%s"),m_strFileName); // 创建以 filename 为名的可执行程序 BOOL bReturn=CreateProcess(NULL,filename,NULL,NULL,FALSE,0,NULL,NULL, &StartupInfo,&ProcessInformation); if(!bReturn) { MessageBox(_T(" 创建失败 ")); } }