读Windows核心编程 - 5

来源:互联网 发布:淘宝网上买的铁观音9.9 编辑:程序博客网 时间:2024/05/06 04:51

        Windows2000 提供了一个新的作业内核对象,使你能够将进程组合在一起,并且创建一个"沙框",以便限制进程能够进程的操作,最好将作业对象视为一个进程的容器。与其他所有内核对象相似,创建作业对象需要调用Handle CreateJobObject(PSECURITY_ATTRIBUTES psa, PCTSTR pszName),第一个参数与其他类似Create*函数相同,第二个参数用于给作业对象命名,使它可以供另一个进程通过OpenJobObject访问。关闭作业对象同样使用CloseHandle函数,应该知道,关闭作业对象并不会使作业中的所有进程终止运行。该作业对象实际上做了删除标记,只有当所有进程全部终止后才撤销。关闭作业对象后,尽管对象没有立即撤销,但是该作业无法被进程访问。通常可以给一个作业加上不同类型的限制:

1. 基本限制和扩展限制,用于防止作业中的进程垄断系统的资源。

2. 基本的UI限制,用于防止作业中的进程改变用户界面。

3. 安全性限制,用于防止作业中的进程访问保密资源(文件,注册表子关键字)

通过下面的代码,可以给作业加上各种限制:

BOOL SetInformationObject(
     Handle hJob,              //标识要限制的作业
     JOBOBJECTINFORMATION JobObjectInformationClass,   //指明要限制的类型,共四种
     PVOID pJobObjectInformation,             //限制设置值的数据结构的地址
     DWORD cdJobObjectInformationLength           //该结构的大小
);

 限制的类型一共四种,对应的PVOID指向的结构体类型分别如下:

基本限制------------JobObjectBasicLimitInformation------------JOBOBJECT_BASIC_LIMIT_INFORMATION

扩展基本限制------JobObjectExtendedLimitInformation-------JOBOBJECT_EXTENDED_LIMIT_INFORMATION

基本UI限制---------JobObjectBasicUIRestrictions---------------JOBOBJECT_BASIC_UI_RESTRICTIONS

安全性限制---------JobObjectSecurityLimitInformation---------JOBOBJECT_SECURITY_LIMIT_INFORMATION

具体每一种提供了哪些限制这里不再详述,可参看核心编程page94。

        对作业实施一些限制后,我们通过CreateProcess创建新的进程,并可以调用AssignProcessToJobObject将该进程指到为某一作业。这里调用CreateProcess时要用CREATE_SUSPENDED标志,因为如果允许子进程立即执行起来,那么它将跑出我们的沙框。因此在我们允许它开始运行之前,我们必须调用AssignProcessToJobObject函数将进程放入我们新建的作业中。调用完AssignProcessToJobObject之后,我们调用ResumeThread函数使新进程在作业的限制下开始运行。一旦进程成为一个作业的一部分,它就不能转到另一个作业。另外,当属于作业中的进程创建了另一个进程后,该进程将自动成为父作业的组成部分。有两种办法可以使新产生的进程不属于该作业:

1. 打开JOBOBJECT_BASIC_LIMIT_INFORMATION的LimitFlags成员中的JOB_OBJECT_BREAKAWAY_OK,告诉系统新产生的进程可以在作业外运行。并且调用CreateProcess时用CREATE_BREAKAWAY_FROM_JOB标志。

2. 打开JOBOBJECT_BASIC_LIMIT_INFORMATION的LimitFlags成员中的JOB_OBJECT_SILENT_BREAKAWAY_OK标志。这样不需要在CreateProcess中传递任何其他标志。

        若要撤销作业中的进程,可用TerminateJobObject,这类似为作业中的每个进程调用TerminateProcess。

        QueryInformationJobObject函数可以用来获取对作业的当前限制,用法与SetInformationObject类似,需要传递限制的类型给第二个参数。这个函数也可以用来获得关于作业的统计信息。方法是为第二个参数传递JobObjectBasicAccountingInformation,并传递JOBOBJECT_BASIC_ACCOUNTING_INFORMATION结构的地址。除此之外,还可以获得I/O统计信息、获得作业中运行的进程的一组进程ID等。可以使用Performance Data Helper函数库(PDH.dll)中的函数来检索作业信息,也可以使用Microsoft Management Console(MMC)来参看作业信息。但是MMC只能为已经命名的作业对象获取性能计数器信息,所以我们调用CreateJobObject时应该创建带有名字的作业对象。

作业通知信息:

         有时候我们需要知道作业中何时生成新进程或者作业中的进程何时终止等消息,比如我们关心的是分配所有CPU的时间是否已经到期,那么可以非常容易地得到这个通知消息。当作业中的进程尚未用完分配的CPU时间时,作业对象就得不到通知。一旦分配的所有CPU时间已经用完,windows就强制撤销作业中的所有进程,并将情况通知作业对象。通过调用WaitForSingleObject就可以容易地跟踪这个事件。但是如果想获得更高级的通知信息,如果进程创建/终止等。如果想要得到这些通知消息,必须将更多的基础结构放入应用程序。特别是,必须创建一个I/O完成端口内核对象,并将作业对象或多个作业对象与完成端口关联起来。然后,必须让一个或多个线程在完成端口上等待作业通知的到来,这样它们才能得到处理。

        一旦创建了I/O完成端口,通过调用SetInformationJobOject函数,就可以将作业与该端口关联起来,如下:

JOBOJECT_ASSOCIATE_COMPLETION_PORT joacp;
joacp.CompletionKey 
= 1;
joacp.CompletionPort 
= hIOCP;
SetInformationJobObject(hJob, JobObjectAssociateCompletionPortInformation, 
&joacp, sizeof(jaocp));

         当上面的代码运行时,系统将监视该作业的运行,当事件发生时,它将事件送往I/O完成端口。线程通过GetQueuedCompletionStatus函数来监控I/O端口。可以监控很多事件的发生,比如:当作业中没有进程运行时、当一个进程添加到作业中、当一个进程终止运行等等情况。具体用法参看核心编程page105。

原创粉丝点击