Windows核心编程(第5版)ch05.doc





《Windows核心编程(第5版)ch05.doc》由会员分享,可在线阅读,更多相关《Windows核心编程(第5版)ch05.doc(19页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第5章 作业第5章 作 业本章内容5.1 对作业中的进程施加限制5.2 将进程放入作业中5.3 终止作业中的所有进程5.4 作业通知5.5 Job Lab示例程序我们经常都需要将一组进程当作单个实体来处理。例如,我们用Visual Studio来构建一个C+项目的时候,它会生成Cl.exe,后者可能必须生成更多的进程(比如编译器每次对源文件进行扫描的时候。 译注:在每次扫描过程中,都对源程序或源程序的中间结果从头到尾扫描一次,并进行相关的加工处理,从而生成新的中间结果或目标程序。)。但是,如果用户希望提前停止构建过程,Visual Studio必须能够以某种方式终止Cl.exe及其所有子进程。
2、虽然这是一个简单而常见的问题,但在Microsoft Windows中解决起来非常难,这是由于Windows没有维护进程之间的父/子关系。具体地说,即使父进程已经终止运行,子进程仍在继续运行。设计一个服务器时,也必须把一组进程当作一个单独的组来处理。例如,一个客户端也许会请求服务器执行一个应用程序并将结果返回给客户端(该应用程序也许会生成自己的子进程)。由于许多客户端都可能连接到此服务器,所以服务器应该以某种方式限制客户端能请求的东西,避免任何一个客户端独占其所有资源。这些限制包括可以分配给客户端请求的最大CPU时间;最小工作集(working set)和最大工作集大小、禁止客户端应用程序关闭
3、计算机以及安全限制。Windows提供了一个作业(job)内核对象,它允许我们将进程组合在一起并创建一个“沙箱”来限制进程能够做什么。最好将作业对象想象成一个进程容器。但是,创建只包含一个进程的作业同样非常有用,因为这样可以对进程施加平时不能施加的限制。 下面是我编写的StartRestrictedProcess函数,该函数将一个进程放入一个作业中,以限制此进程具体能够做哪些事情,如下所示:void StartRestrictedProcess() / Check if we are not already associated with a job./ If this is the case
4、, there is no way to switch to/ another job.BOOL bInJob = FALSE;IsProcessInJob(GetCurrentProcess(), NULL, &bInJob);if (bInJob) MessageBox(NULL, TEXT(Process already in a job),TEXT(), MB_ICONINFORMATION | MB_OK);return;/ Create a job kernel object.HANDLE hjob = CreateJobObject(NULL,TEXT(Wintellect_Re
5、strictedProcessJob);/ Place some restrictions on processes in the job./ First, set some basic restrictions.JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = 0 ;/ The process always runs in the idle priority class.jobli.PriorityClass = IDLE_PRIORITY_CLASS;/ The job cannot use more than 1 second of CPU time.j
6、obli.PerJobUserTimeLimit.QuadPart = 10000; / 1 sec in 100-ns intervals/ These are the only 2 restrictions I want placed on the job (process).jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS| JOB_OBJECT_LIMIT_JOB_TIME;SetInformationJobObject(hjob, JobObjectBasicLimitInformation, &jobli,sizeof(jobli
7、);/ Second, set some UI restrictions.JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE; / A fancy zero/ The process cant log off the system.jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;/ The process cant access USER objects (such as other win
8、dows)/ in the system.jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;SetInformationJobObject(hjob, JobObjectBasicUIRestrictions, &jobuir,sizeof(jobuir);/ Spawn the process that is to be in the job./ Note: You must first spawn the process and then place the process in/ the job. This means th
9、at the process thread must be initially/ suspended so that it cant execute any code outside of the jobs/ restrictions.STARTUPINFO si = sizeof(si) ;PROCESS_INFORMATION pi;TCHAR szCmdLine8;_tcscpy_s(szCmdLine, _countof(szCmdLine), TEXT(CMD);BOOL bResult = CreateProcess( NULL, szCmdLine, NULL, NULL, FA
10、LSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);/ Place the process in the job./ Note: If this process spawns any children, the children are/ automatically part of the same job.AssignProcessToJobObject(hjob, pi.hProcess);/ Now we can allow the child process thread to execute code.R
11、esumeThread(pi.hThread);CloseHandle(pi.hThread);/ Wait for the process to terminate or/ for all the jobs allotted CPU time to be used.HANDLE h2;h0 = pi.hProcess;h1 = hjob;DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);switch (dw WAIT_OBJECT_0) case 0:/ The process has terminated.break;case
12、 1:/ All of the jobs allotted CPU time was used.break;FILETIME CreationTime;FILETIME ExitTime;FILETIME KernelTime;FILETIME UserTime;TCHAR szInfoMAX_PATH;GetProcessTimes(pi.hProcess, &CreationTime, &ExitTime,&KernelTime, &UserTime);StringCchPrintf(szInfo, _countof(szInfo), TEXT(Kernel = %u | User = %
13、un),KernelTime.dwLowDateTime / 10000, UserTime.dwLowDateTime / 10000);MessageBox(GetActiveWindow(), szInfo, TEXT(Restricted Process times),MB_ICONINFORMATION | MB_OK);/ Clean up properly.CloseHandle(pi.hProcess);CloseHandle(hjob); 现在来解释StartRestrictedProcess的工作方式。首先,函数将NULL作为第二个参数传给以下函数,验证当前进程是否在一个现
14、有的作业控制之下运行:BOOL IsProcessInJob( HANDLE hProcess, HANDLE hJob, PBOOL pbInJob);如果进程已与一个作业关联,就无法将当前进程或者它的任何子进程从作业中去除。这个安全特性可以确保进程无法摆脱对它施加的限制。 警告 默认情况下,在Windows Vista中通过Windows资源管理器来启动一个应用程序时,进程会自动同一个专用的作业关联,此作业的名称使用了PCA字符串前缀。正如本章稍后的“作业通知”一节要讲述的那样,作业中的一个进程退出时,我们是可以接收到一个通知的。所以,一旦通过Windows资源管理器启动的一个老版本的应用
15、程序 译注:即不是为Windows Vista开发的应用程序。出现问题,就会触发Program Compatibility Assistant(程序兼容性助手)。如果应用程序需要创建像本章最后展示的Job Lab程序那样的一个作业,只能说我们运气不太好。这个创建注定会失败,因为进程已经关联了带PCA前缀的作业对象。Windows Vista提供这个特性的目的纯粹是为了检测兼容性问题。所以,如果我们已经像第4章描述的那样为应用程序定义了一个清单(manifest),Windows资源管理器就不会将我们的进程同带PCA前缀的作业关联,它会假定我们已经解决了任何可能出现的兼容性问题。但是,在需要调试
16、应用程序的时候,如果调试器是从Windows资源管理器启动的,即使我们的应用程序有一个清单(mainifest),它也会从调试器继承带PCA前缀的作业。一个简单的解决方案是从命令行而不是Windows资源管理器中启动调试器。在这种情况下,我们的进程就不会与作业关联。然后,我通过以下调用来创建一个新的作业内核对象:HANDLE CreateJobObject( PSECURITY_ATTRIBUTES psa, PCTSTR pszName);和所有内核对象一样,第一个参数将安全信息与新的作业对象关联,然后告诉系统,是否希望返回的句柄可被继承。最后一个参数对此作业对象进行命名,使其能够由另一个进
17、程通过OpenJobObject函数(详见本章后文)进行访问,如下所示:HANDLE OpenJobObject( DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName);和往常一样,如果确定在自己的代码中不再访问作业对象,就必须调用CloseHandle来关闭它的句柄。这一点在前面的StartRestrictedProcess函数的末尾有所体现。务必记住,关闭一个作业对象,不会迫使作业中的所有进程都终止运行。作业对象实际只是加了一个删除标记,只有在作业中的所有进程都已终止运行之后,才会自动销毁。注意,关闭作业的句柄会导致所有进程
18、都不可访问此作业,即使这个作业仍然存在。如以下代码所示:/ Create a named job object.HANDLE hJob = CreateJobObject(NULL, TEXT(Jeff);/ Put our own process in the job.AssignProcessToJobObject(hJob, GetCurrentProcess();/ Closing the job does not kill our process or the job./ But the name (Jeff) is immediately disassociated with th
19、e job.CloseHandle(hJob);/ Try to open the existing job.hJob = OpenJobObject(JOB_OBJECT_ALL_ACCESS, FALSE, TEXT(Jeff);/ OpenJobObject fails and returns NULL here because the name (Jeff)/ was disassociated from the job when CloseHandle was called./ There is no way to get a handle to this job now. 5.1
20、对作业中的进程施加限制创建好一个作业之后,接着一般会根据作业中的进程能够执行哪些操作来建立一个沙箱(即施加限制 译注:原著中用了restrition和limit 两个词来表示限制(约束),这里前者译为限制,后者译为限额,以示区分。)。可以向作业应用以下几种类型的限制:l 基本限额和扩展基本限额,用于防止作业中的进程独占系统资源。l 基本的UI限制,用于防止作业内的进程更改用户界面。l 安全限额,用于防止作业内的进程访问安全资源(文件、注册表子项等)。可以通过调用以下函数向作业施加限制:BOOL SetInformationJobObject( HANDLE hJob, JOBOBJECTINF
21、OCLASS JobObjectInformationClass, PVOID pJobObjectInformation, DWORD cbJobObjectInformationSize);第一个参数指定要限制的作业。第二个参数是一个枚举类型,指定了要施加的限制的类型。第三个参数是一个数据结构的地址,该数据结构中包含具体的限制设置。第四个参数指出此数据结构的大小(用于版本控制)。表5-1总结了如何设置这些限制。表5-1 限制类型限制类型第二个参数的值第三个参数所对应的数据结构基本限额JobObjectBasicLimitInformationJOBOBJECT_BASIC_LIMIT_IN
22、FORMATION扩展后的基本限额JobObjectExtendedLimitInformationJOBOBJECT_EXTENDED_LIMIT_INFORMATION基本的UI限制JobObjectBasicUIRestrictionsJOBOBJECT_BASIC_UI_RESTRICTIONS安全限额JobObjectSecurityLimitInformationJOBOBJECT_SECURITY_LIMIT_INFORMATION在我编写的StartRestrictedProcess函数中,只对作业设置了一些基本的限制。我分配了一个JOBOBJECT_BASIC_LIMIT_I
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Windows 核心 编程 ch05

限制150内