多进程(1)

创建新进程

        Windows 是以对象的方式来管理进程的,它由 Win32 子系统来创建和维护,并且可以由此进程的句柄来进行管理。进程的创建一般是在一个进程的线程中调用函数CreateProcess(  )来创建的,这个进程可以和原进程共享资源(例如句柄和变量),而且在Windows 中,这两个进程不存在的父子关系,即使原进程终止后,这个新进程仍然可以继续执行。

1.数据结构

(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:返回一个全局线程标识符。该标识符用于标识一个线程。从线程被创建到终止,该值始终有效。

 2.建立线程

        可以使用 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。

 
1.取得进程的句柄或ID


函数 GetCurrentProcess 可以取得当前进程的句柄,其原型为:
 
HANDLE  GetCurrentProcess(VOID)
 
这个函数返回一个指向当前进程的句柄,但这是一个伪句柄,即仅仅只能打开此进程对象,增加此对象的引用计数,这个伪句柄只能在当前进程中使用,而不能在其他进程中利用此句柄对这个进程进行操作。若在别的进程中对当前这个进程进行操作,可调用函数DuplicateHandle( )把这个伪句柄转换成一个真正的句柄。
函数 DWORD GetCurrentProcessID(VOID)可以取得当前进程的 ID,有一些 API 函数需要用到进程 ID。


2.  取得和设置进程的优先级

        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(" 创建失败 ")); 
	} 
}


 

 

 

你可能感兴趣的:(多进程(1))