Windows核心编程-作业

原文链接:http://zhujiangtao.com/?p=983

作业

  • 作业
  • 一个简单例程
  • CreateJobObject 创建作业
  • 作业限制和 SetInformationJobObject
  • AssignProcessToJobObject 将进程添加到作业
  • 终止作业
  • QueryInformationJobObject 查询作业的统计信息
  • 作业的通知消息

(1) 作业

[MSDN] 作业对象允许一组进程被当做一个单元进行管理。作业对象是可命名的、安全的、共享的对象,它能够控制它包含的所有进程的属性。执行在作业上的操作会影响作业包含的所有进程。

作业可视为进程的容器,可以对其中的所有进程加上限制条件。

使用CrateJobObject函数,创建一个作业

使用SetInformationJobObject函数,为作业添加限制条件

使用AssignProcessToJobObject函数,将进程添加到作业

使用IsProcessInJob函数,判断一个进程是否属于一个作业。

(2) 一个简单例程

 1 #include <windows.h>
 2 #include <tchar.h>
 3
 4 int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE,PWSTR lpCmdLine,int nShowCmd){
 5
 6     //创建一个作业内核对象
 7     HANDLE hJob = CreateJobObject(NULL,NULL); //
 8
 9     ////////////////////////////////////////////////////////////
10     //为作业添加一些基本限制
11
12     //基本限制结构体
13     JOBOBJECT_BASIC_LIMIT_INFORMATION jobli = {0};
14
15     //作业的优先级
16     jobli.PriorityClass = IDLE_PRIORITY_CLASS; //
17
18     //作业的CPU时间限制
19     jobli.PerJobUserTimeLimit.QuadPart = 10000000; //1秒,单位是100纳秒
20
21     //指明限制条件
22     jobli.LimitFlags = JOB_OBJECT_LIMIT_PRIORITY_CLASS|JOB_OBJECT_LIMIT_JOB_TIME;
23
24     //设定作业限制
25     SetInformationJobObject(hJob,JobObjectBasicLimitInformation,&jobli,sizeof(jobli));
26
27     ////////////////////////////////////////////////////////////
28     //为作业添加一些基本UI限制
29
30     //基本UI限制结构体
31     JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;
32
33     //初始无限制
34     jobuir.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE; //
35
36     //增加限制:作业(进程)不能注销操作系统
37     jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
38
39     //增加限制:作业(进程)不能访问 系统的用户对象(如其他窗口)
40     jobuir.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
41
42     //设定作业限制
43     SetInformationJobObject(hJob,JobObjectBasicUIRestrictions,&jobuir,sizeof(jobuir));
44
45     ////////////////////////////////////////////////////////////
46     //创建进程,并添加到作业中。进程初始化时必须是挂起状态,保证在添加到作业前不会执行任何代码
47
48     //创建进程
49     STARTUPINFO si={sizeof(si)};
50     PROCESS_INFORMATION pi;
51     CreateProcess(_T("C:\\Windows\\System32\\cmd.exe"),NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi); //CREATE_SUSPENDED
52
53     //将进程添加到作业
54     AssignProcessToJobObject(hJob,pi.hProcess);
55
56     //唤醒进程(的主线程)
57     ResumeThread(pi.hThread);
58
59     //关闭句柄
60     CloseHandle(pi.hThread);
61
62     ////////////////////////////////////////////////////////////
63     //等待进程结束或作业CPU时间耗完
64     HANDLE h[2];
65     h[0] = pi.hProcess;
66     h[1] = hJob;
67
68     DWORD ret = WaitForMultipleObjects(2,h,FALSE,INFINITE);
69     switch(ret-WAIT_OBJECT_0){
70         case 0:
71             //进程结束
72             MessageBox(NULL,_T("进程结束"),_T("提示"),MB_OK);
73             break;
74         case 1:
75             //作业分配的CPU时间耗完
76             MessageBox(NULL,_T("时间耗尽"),_T("提示"),MB_OK);
77             break;
78     }
79
80     //关闭句柄
81     CloseHandle(pi.hProcess);
82     CloseHandle(hJob);
83
84     return 0;
85 }

(3) CreateJobObject 创建作业

HANDLE WINAPI CreateJobObject( //创建作业内核对象

    __in_opt  LPSECURITY_ATTRIBUTES lpJobAttributes, //安全结构体

    __in_opt  LPCTSTR lpName   //名称,可以为NULl

    );

(4)作业限制 和 SetInformationJobObject

作业限制类型有:基本限制、扩展限制、UI限制、安全性限制

使用SetInformationJobObject可以为作业指定限制。

1 BOOL WINAPI SetInformationJobObject(  //设置作业限制
2     __in  HANDLE hJob,                            //要添加限制的作业
3     __in  JOBOBJECTINFOCLASS JobObjectInfoClass,  //限制的类型
4     __in  LPVOID lpJobObjectInfo,                 //限制的值
5     __in  DWORD cbJobObjectInfoLength             //限制的值的长度
6     );

限制类型

说明

第二个参数的值

第三个参数的结构

基本限制

CPU分配限制

JobObjectBasicLimitInformation

JOBOBJECT_BASIC_LIMIT_INFORMATION

扩展限制
基本限制+内存分配限制
JobObjectExtendedLimitInformation

JOBOBJECT_EXTENDED_LIMIT_INFORMATION

基本UI限制
防止作业中进程改变UI
JobObjectBasicUIRestictions

JOBOBJECT_BASIC_UI_RESTRICTIONS

安全性限制
防止作业中进程访问保密资源
JobObjectSecurityLimitInformation

JOBOBJECT_SECURITY_LIMIT_INFORMATION

[1] 基本限制

 1 //基本限制:CPU限制
 2 typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
 3     LARGE_INTEGER PerProcessUserTimeLimit; //如果LimitFlags含有JOB_OBJECT_LIMIT_PROCESS_TIME,则此参数表示分配给每个进程的用户模式执行时间,单位100ns.超时进程会被终止
 4     LARGE_INTEGER PerJobUserTimeLimit;     //如果LimitFlags含有JOB_OBJECT_LIMIT_JOB_TIME,则此参数表示分配给作业的用户模式执行时间,超时作业会被终止
 5     DWORD         LimitFlags;              //指明哪些限制对作业有效
 6     SIZE_T        MinimumWorkingSetSize;   //如果LimitFlags含有JOB_OBJECT_LIMIT_WORKINGSET,则此参数表示作业中每个进程的最小工作集大小
 7     SIZE_T        MaximumWorkingSetSize;   //同上,最大工作集大小
 8     DWORD         ActiveProcessLimit;      //如果LimitFlags含有JOB_OBJECT_LIMIT_ACTIVE_PROCESS,则此参数表示作业中可以同时运行的最大进程数量
 9     ULONG_PTR     Affinity;                //如果LimitFlags含有JOB_OBJECT_LIMIT_AFFINITY,则此参数表示能够运行的进程的CPU子集
10     DWORD         PriorityClass;           //如果LimitFlags含有JOB_OBJECT_LIMIT_PRIORITY_CLASS,则此参数表示作业中所有进程的优先级
11     DWORD         SchedulingClass;         //如果LimitFlags含有JOB_OBJECT_LIMIT_SCHEDULING_CLASS,则此参数表示相同优先级的作业的调度优先级(0-9,默认5),值越大,CPU时间越长
12 } JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;

[2] 扩展限制

1 //扩展限制:基本限制+内存限制
2 typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
3     JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; //基本限制
4     IO_COUNTERS                       IoInfo;                //保留不用。IO计数器
5     SIZE_T                            ProcessMemoryLimit;    //每个进程能使用的内存量(“基本限制”参数的LimitFlags需含有JOB_OBJECT_LIMIT_PROCESS_MEMORY)
6     SIZE_T                            JobMemoryLimit;        //作业(所有进程)能使用的内存量(“基本限制”参数的LimitFlags需含有JOB_OBJECT_LIMIT_JOB_MEMORY )
7     SIZE_T                            PeakProcessMemoryUsed; //只读。单个进程需要使用的内存最大值
8     SIZE_T                            PeakJobMemoryUsed;     //只读。作业需要使用的内存最大值
9 } JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;

[3] 基本UI限制

1 //基本UI限制
2 typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS {
3     DWORD UIRestrictionsClass; //下表标志中一个或是组合
4 } JOBOBJECT_BASIC_UI_RESTRICTIONS, *PJOBOBJECT_BASIC_UI_RESTRICTIONS;

说明

JOB_OBJECT_UILIMIT_EXITWINDOWS

防止进程通过ExitWindowsEx函数退出、关闭、重启或关闭系统电源

JOB_OBJECT_UILIMIT_READCLIPBOARD

防止进程读取剪切板的内容
JOB_OBJECT_UILIMIT_WRITECLIPBOARD 防止进程写剪切板内容
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS
防止进程通过SystemParametersInfor函数来改变系统参数

JOB_OBJECT_UILIMIT_DISPLAYSETTINGS

防止进程通过ChangeDisplaySettings函数来改变显示设置

JOB_OBJECT_UILIMIT_GLOBALATOMS
防止进程访问全局的基本结构表,为作业分配自己的基本结构表,作业中进程只能访问该表。

JOB_OBJECT_UILIMIT_DESKTOP
防止进程使用CreateDesktop或SwitchDesktop函数创建或转换桌面

JOB_OBJECT_UILIMIT_HANDLES
防止进程使用作业外部的进程创建的用户对象的句柄(如HWND)

[4] 安全性限制

Windows XP(不包括XP)之后的系统不再支持该限制,需要为每个进程单独指定安全设置。

(5)AssignProcessToJobObject 将进程添加到作业

要添加到作业的进程在创建时,需使用CREATE_SUSPEND标志,防止加入作业前进程执行任何代码。

1 BOOL WINAPI AssignProcessToJobObject(  __in  HANDLE hJob,    //作业句柄
2     __in  HANDLE hProcess //进程句柄
3     );

一个进程加入到一个作业后,不能再转到另一个作业。

作业中的进程生成的新进程会自动成为作业的一部分。可以通过下面两种方法改变这种特性:

[1] 打开JOBOBJECT_BASIC_LIMIT_INFROMATION 的LimitFlags成员的JOB_OBJECT_BREAKAWAY_OK标志,告诉系统,新生成的进程可以在作业外部运行。同时使用CREATE_BREAKAWAY_FROM_JOB 标志调用CreateProcess创建新进程

[2] 打开JOBOBJECT_BASIC_LIMIT_INFROMATION 的LimitFlags成员的JOB_OBJECT_SILENT_BREAKAWAY_OK标志,告诉系统,新生成的进程可以在作业外部运行。

(6) 终止作业

1 BOOL WINAPI TerminateJobObject(
2     __in  HANDLE hJob,    //作业
3     __in  UINT uExitCode  //退出码。作业中所有进程的退出码自动设为uExitCode
4     );

(7) QueryInformationJobObject 查询作业的统计信息

(8) 作业的通知消息

创建一个IO完成端口(IO Completion Port)内核对象,然后将作业对象或多个作业对象与完成端口关联起来(使用SetInformationJobObject函数),然后让一个或多个线程在完成端口上等待作业通知的到来。

  1 #include <windows.h>
  2 #include <process.h>  //_beginthreadex
  3 #include <tchar.h>
  4
  5 #define CMPKEY_JOBOBJECT 1
  6 #define CMPKEY_TERMINATE 2
  7
  8 typedef unsigned (__stdcall *PTHREAD_START) (void *);
  9
 10 //IO完成端口监听线程回调函数
 11 DWORD WINAPI JobNotify(LPVOID lpParam)
 12 {
 13     HANDLE hIOCP = (HANDLE)lpParam;
 14
 15     while (TRUE)
 16     {
 17         DWORD dwBytesTransferred;
 18         ULONG_PTR CompKey;
 19         LPOVERLAPPED po;
 20
 21         //从IO完成端口中获取一个消息
 22         GetQueuedCompletionStatus(hIOCP,&dwBytesTransferred,&CompKey,&po,INFINITE);
 23
 24         //退出消息
 25         if (CompKey == CMPKEY_TERMINATE)
 26         {
 27             MessageBox(NULL,_T("监听线程退出"),_T("提示"),MB_OK);
 28             break;
 29         }
 30
 31         //来自作业对象hJob的消息
 32         if(CompKey == CMPKEY_JOBOBJECT)
 33         {
 34             MessageBox(NULL,_T("收到来自作业的消息"),_T("提示"),MB_OK);
 35
 36             switch(dwBytesTransferred){
 37             case JOB_OBJECT_MSG_END_OF_JOB_TIME:
 38                 MessageBox(NULL,_T("作业限制时间耗尽"),_T("提示"),MB_OK);
 39                 break;
 40             case JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
 41                 {
 42                     TCHAR szProcessName[MAX_PATH];
 43                     HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,(DWORD)po);
 44
 45                     if(hProcess == NULL){
 46                         _stprintf(szProcessName,_T("%s"),_T("未知进程名"));
 47                     }
 48                     else{
 49                         DWORD dwSize = (DWORD)MAX_PATH;
 50                         QueryFullProcessImageName(hProcess,0,szProcessName,&dwSize);
 51                         CloseHandle(hProcess);
 52                     }
 53
 54                     TCHAR info[MAX_PATH];
 55                     _stprintf(info,_T("进程%s(ID=%d)限制时间耗尽 "),szProcessName,po);
 56
 57                     MessageBox(NULL,info,_T("提示"),MB_OK);
 58                 }
 59                 break;
 60             case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
 61                 MessageBox(NULL,_T("运行的进程超过限制"),_T("提示"),MB_OK);
 62                 break;
 63             case JOB_OBJECT_MSG_NEW_PROCESS:
 64                 MessageBox(NULL,_T("作业中产生新进程"),_T("提示"),MB_OK);
 65                 break;
 66             case JOB_OBJECT_MSG_EXIT_PROCESS:  {
 67                     TCHAR szProcessName[MAX_PATH];
 68                     HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,(DWORD)po);
 69
 70                     if(hProcess == NULL){
 71                         _stprintf(szProcessName,_T("%s"),_T("未知进程名"));
 72                     }
 73                     else{
 74                         DWORD dwSize = (DWORD)MAX_PATH;
 75                         QueryFullProcessImageName(hProcess,0,szProcessName,&dwSize);
 76                         CloseHandle(hProcess);
 77                     }
 78
 79                     TCHAR info[MAX_PATH];
 80                     _stprintf(info,_T("进程%s(ID=%d)终止 "),szProcessName,po);
 81
 82                     MessageBox(NULL,info,_T("提示"),MB_OK);
 83                 }
 84                 break;
 85             }
 86         }
 87     }
 88     return 0;
 89 }
 90
 91 int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE,PWSTR lpCmdLine,int nShowCmd){
 92
 93     //创建一个作业内核对象
 94     HANDLE hJob = CreateJobObject(NULL,NULL); //
 95
 96     //创建一个IO完成端口
 97     HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
 98
 99     //创建一个线程监听IO完成端口通知消息
100     HANDLE hThreadIOCP = (HANDLE)_beginthreadex(NULL,0,(PTHREAD_START)JobNotify,(LPVOID)hIOCP,0,NULL);
101
102     //将IO完成端口与作业关联
103     JOBOBJECT_ASSOCIATE_COMPLETION_PORT jobacp;
104     jobacp.CompletionKey = (PVOID)CMPKEY_JOBOBJECT;  //任意一个全局唯一的值
105     jobacp.CompletionPort = hIOCP;                   //IO完成端口句柄
106     SetInformationJobObject(hJob,JobObjectAssociateCompletionPortInformation,&jobacp,sizeof(jobacp)); //关联
107
108     ////////////////////////////////////////////////////////////
109     //创建进程,并添加到作业中。进程初始化时必须是挂起状态,保证在添加到作业前不会执行任何代码
110
111     STARTUPINFO si={sizeof(si)};
112     PROCESS_INFORMATION pi;
113     CreateProcess(_T("C:\\Windows\\System32\\cmd.exe"),NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi); //CREATE_SUSPENDED
114     AssignProcessToJobObject(hJob,pi.hProcess);//将进程添加到作业
115     MessageBox(NULL,_T("111"),_T("Tips"),MB_OK);
116     ResumeThread(pi.hThread);//唤醒进程(的主线程)
117     CloseHandle(pi.hThread); //关闭句柄
118     CloseHandle(pi.hProcess);
119     MessageBox(NULL,_T("MESSAGE"),_T("Tips"),MB_OK);
120
121     //发送一条消息给IO完成端口,结束IO完成端口线程
122     PostQueuedCompletionStatus(hIOCP,0,CMPKEY_TERMINATE,NULL);
123
124     //等待IO完成端口线程终止
125     WaitForSingleObject(hThreadIOCP,INFINITE);
126
127     //关闭句柄
128     CloseHandle(hIOCP);
129     CloseHandle(hThreadIOCP);
130     CloseHandle(hJob);
131     return 0;
132 }
时间: 2024-10-08 05:25:59

Windows核心编程-作业的相关文章

【转】《windows核心编程》读书笔记

这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入,但应该是合理的.开头几章由于我追求简洁,往往是很多单独的字句,后面的内容更为连贯. 海量细节. 第1章    错误处理 1.         GetLastError返回的是最后的错误码,即更早的错误码可能被覆盖. 2.         GetLastError可能用于描述成功的原因(CreatEvent)

《Windows核心编程》读书笔记 上

[C++]<Windows核心编程>读书笔记 这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入,但应该是合理的.开头几章由于我追求简洁,往往是很多单独的字句,后面的内容更为连贯. 海量细节. 第1章    错误处理 1.         GetLastError返回的是最后的错误码,即更早的错误码可能被覆盖. 2.         GetLas

回忆读windows 核心编程

看<windows 核心编程> 第五版到纤程了,下一章节即将介绍内存体系编程.如果做window平台下的开发,我感觉此书一定要读.记得开始讲解了window的基础,然后讲解内核对象.内核对象包括,进程,作业,线程,事件,临界点,互斥体等.个人认为还是比较详细,里面的内容无法详细的说出,强烈window下开发的读完次数,今天晚上开启内存体系阅读,希望自己认认真真的读完此书,可能以后不做window平台的开发,但也能有增长只是.只是读书读的太慢,从七月份到12月份,才读了一半,可能最近比忙的原故吧

读书笔记----《windows核心编程》第三章 内核对象1(句柄与安全性)

最近一直没有更新博客,因为一直在想一个问题,内核对象这一章内容很多很重要,自己没有掌握好也没有把握写好这一章,最后还是决定能写多少写多少,一面写一面学,后续学到新的再更新吧; <windows核心编程>提了几种内核对象: 访问令牌对象:与windows的安全性有关,目前不是很懂,了解后再写; 事件对象: Event对象,可跨进程同步; 由CreateEvent创建; 文件对象: File对象,比较常见; 由CreateFile创建; 文件映射对象: 通过文件映射可以方便的操作文件(如同文件数据

C++Windows核心编程读书笔记

转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔记": 关键词:c++windows 核心 编程 读书笔记 这篇笔记是我在读<windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和windows实际机制可能有出入,但应该是合理的.开头几章由于我追求简洁

【windows核心编程】DLL相关(2)

关于DLL的延迟加载 延迟加载DLL,使用的是隐式加载方式,当为exe使用的DLL指定为延迟加载的时候,连接器会将exe的[导入段]中去除该DLL的相关信息,同时在exe中嵌入一个新的[延迟加载段]表示要从该DLL中导入哪些函数. 通过让对延迟加载函数的调用跳转到delayimp.lib中的__delayLoadHelper2函数,来完成对延迟加载的DLL的解析. 当exe中第一次调用了一个延迟加载的DLL中的某个导出函数时,加载器才会将该DLL加载到进程地址空间中.需要注意的是:虽然此时已经加

《windows核心编程系列》十八谈谈windows钩子

windows应用程序是基于消息驱动的.各种应用程序对各种消息作出响应从而实现各种功能. windows钩子是windows消息处理机制的一个监视点,通过安装钩子能够达到监视指定窗体某种类型的消息的功能.所谓的指定窗体并不局限于当前进程的窗体,也能够是其它进程的窗体.当监视的某一消息到达指定的窗体时,在指定的窗体处理消息之前,钩子函数将截获此消息,钩子函数既能够加工处理该消息,也能够不作不论什么处理继续传递该消息.使用钩子是实现dll注入的方法之中的一个.其它经常使用的方法有:注冊表注入,远程线

【windows核心编程】DLL相关

DLL相关的东西 1.DLL的加载方式 隐式: #pragma comment(lib, "XX.lib"); 编译器去查找名为XX.dll的DLL,除了名字相同,该DLL和该LIB的GUID也相同. 显式: HINSTANCE   hInst = LoadLibrary(TEXT("XX.dll")); if(NULL == hInst)  retrun; HINSTANCE hInst = LoadLibrary(TEXT("XX.dll")

《Windows核心编程》第5版 学习进度备忘

学习资源:<Windows核心编程>第5版 知识基础支持: 跳过的内容: 1. 知识要点: 1: 注意事项: 1. 不理解知识点: 1. 进度: 1.2014-08-10,前两章结束,接下来“第3章内核对象” <Windows核心编程>第5版 学习进度备忘,布布扣,bubuko.com