Windows核心编程笔记(3)--作业

/*1、如果进程已经与一个作业相关联,就无法将当前进程及其任何子进程从作业中移除,这个安全特性可以保证
/*	进程无法摆脱对它施加的限制。
/*2、在调试程序时,调试器是从资源管理器启动的,程序会从调试器继承带“PCA”前缀的作业。因此,调试程序
/*	时总是显示进程已经加入了作业。使用命令行来运行程序时就不会有这个问题了。
/*3、关闭一个作业对象,并不会终止作业内所有的进程。作业对象实际上只是加了一个删除标记,只有在作业中
/*	所有进程都终止后,才会自动销毁。
/*4、可以向作业引用以下几种限制:(SetInformationJobObject函数来实现)
	4.1 基本限制和额外限制,用于防止作业中的进程独占系统资源;
	4.2 基本的UI限制,用于防止作业内的进程更改用户界面;
	4.3 安全限额,用于防止作业内的进程访问安全资源(文件、注册表子项等)
/*5、一旦进程已经加入一个作业,就不能再将其加入其他作业,该进程说创建的子进程也将处于其作业的限制内。
/*	可以给作业加上JOB_OBJECT_LIMIT_BREAKAWAY_OK限制,并在创建子进程时加上CREATE_BREAKAWAY_FROM_JOB标
/*	识,这样子进程就不会受到父进程作业的限制了。
/*6、终止作业中所有进程的方法,	TerminateJobObject( __in HANDLE hJob, __in UINT uExitCode )函数终止作业。
*/

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using std::cout;
using std::endl;

BOOL	AddThreadToJob();
int _tmain(int argc, _TCHAR* argv[])
{
	AddThreadToJob();
	return 0;
}

BOOL AddThreadToJob()
{
	BOOL bResult = FALSE;
	HANDLE hJob = NULL;
	try
	{
		BOOL bInJob = FALSE;
		//DWORD dwPid = GetCurrentProcessId();
		//这里是获取进程的真实句柄
		//HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
		//GetCurrentProcess()返回的是伪句柄0xffffffff,但是本身是没有错误的
		BOOL bRet = IsProcessInJob(GetCurrentProcess(), NULL, &bInJob);
		//CloseHandle(hProcess);
		if ( bInJob )
		{
			JOBOBJECT_BASIC_PROCESS_ID_LIST jbril;
			memset(&jbril, 0, sizeof(jbril));
			DWORD dwLen = 0;
			bRet = QueryInformationJobObject(NULL, JobObjectBasicProcessIdList, (LPVOID)&jbril, 				sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST), &dwLen);
			throw L"当前进程已经加入到作业中!";
		}
		hJob = CreateJobObject(NULL, L"TestJob");
		if ( NULL == hJob )
		{
			throw L"创建作业失败!";
		}
		if ( GetLastError() == ERROR_ALREADY_EXISTS )
		{
			throw L"同名作业已经创建!";
		}
		cout<<"给作业添加限制"<<endl;
		//设置作业基本限制
		JOBOBJECT_BASIC_LIMIT_INFORMATION jbli = {0};
		jbli.PriorityClass					= IDLE_PRIORITY_CLASS;
		//对于进程占用时间超过分配时间的任何进程,系统将自动终止其运行
		jbli.PerJobUserTimeLimit.QuadPart	= 10000;
		jbli.LimitFlags						= JOB_OBJECT_LIMIT_PRIORITY_CLASS|JOB_OBJECT_LIMIT_JOB_TIME;
		SetInformationJobObject(hJob, JobObjectBasicLimitInformation, (LPVOID)&jbli, sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION));
		//设置作业UI限制
		cout<<"设置作业UI限制"<<endl;
		JOBOBJECT_BASIC_UI_RESTRICTIONS jbur;
		jbur.UIRestrictionsClass	= JOB_OBJECT_UILIMIT_EXITWINDOWS;	//不能关闭计算机
		jbur.UIRestrictionsClass	|= JOB_OBJECT_UILIMIT_HANDLES;		//不能访问系统里的其他对象句柄
		SetInformationJobObject(hJob, JobObjectBasicUIRestrictions, (LPVOID)&jbur, sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS));
		//首先必须创建进程,然后挂起这个进程使他不能执行任何代码,然后才能加入作业中(确保进程在进入作业前不自信任何代码)
		//不然加入作业限制这个进程也就没意义了
		STARTUPINFO si;
		memset(&si, 0, sizeof(STARTUPINFO));
		si.cb	= sizeof(STARTUPINFO);
		PROCESS_INFORMATION pi;
		memset(&pi, 0, sizeof(PROCESS_INFORMATION));
		cout<<"创建一个新的进程"<<endl;
		bRet = CreateProcess(L"update.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED|CREATE_NEW_CONSOLE, NULL, 			NULL, &si, &pi);
		if ( !bRet )
			throw L"创建进程失败!";
		cout<<"子进程创建完毕"<<endl;
		//把这个进程加入到作业中去
		AssignProcessToJobObject(hJob, pi.hProcess);
		//现在可以恢复这个进程,让他开始执行代码了
		ResumeThread(pi.hThread);
		CloseHandle(pi.hThread);
		//等待进程终止,或者作业所申请的CPU时间都用完
		HANDLE h[2];
		h[0]	= pi.hProcess;
		h[1]	= hJob;
		cout<<"开始等待进程执行完毕或者作业CPU使用完"<<endl;
		DWORD dwRet = WaitForMultipleObjects(2, h, FALSE, INFINITE);
		switch( dwRet-WAIT_OBJECT_0 )
		{
		case 0://进程终止
			{
				int a = 0;
				cout<<"进程终止"<<endl;;
				break;
			}
		case 1://作业的CPU时间用完
			{
				int a = 0;
				cout<<"作业的CPU时间用完"<<endl;
				break;
			}
		}
		CloseHandle(pi.hProcess);
		//获取进程执行时间信息
		FILETIME createTime, exitTime, kernelTime, usedTime;
		GetProcessTimes(pi.hProcess, &createTime, &exitTime, &kernelTime, &usedTime);
		WCHAR szBuffer[256] = {0};
		swprintf_s(szBuffer, 256, L"createTime=%u,exitTime=%u,kernelTime=%u,usedTime=%u", 			createTime.dwLowDateTime/1000, exitTime.dwLowDateTime/10000, 			kernelTime.dwLowDateTime/10000, usedTime.dwLowDateTime/10000);
		MessageBox(NULL, szBuffer, L"结束:", MB_OK);
		bResult = TRUE;
	}
	catch(WCHAR* pMsg)
	{
		MessageBox(NULL, pMsg, NULL, 0);
	}
	if ( hJob )
		CloseHandle(hJob);
	return bResult;
}
最后,运行该实例时需要从命令行来,因为资源管理器启动会默认加入系统作业。(上文有说明)

时间: 2024-08-01 20:38:20

Windows核心编程笔记(3)--作业的相关文章

Windows核心编程笔记(1)

最近工作比较闲了,一直没来得及看的核心编程最近开始看了,分享下笔记. 1.内核句柄用完不释放一定会造成内存泄漏吗? 不一定,内核句柄在进程退出时会被系统释放掉(遍历内核句柄表,只要每个句柄指向的内核对象的引用计数为0,内核就会销毁该对象,适用于所有的内核对象.资源(GDI对象在内).内存块): 2.内核对象如何关闭? 调用CloseHandle(),内核会查找该进程的句柄表,如果没找到该句柄,返回FALSE(Debug下抛出异常);如果找到,则使该句柄指向的内核对象引用计数减一,若引用计数为0,

Windows核心编程笔记(7)----内核模式下的线程同步

1.内核对象同步与用户模式下同步对比 使用内核对象的唯一缺点就是性能,调用内核对象函数时,调用线程必须从用户模式切换到内核模式,这种切换是相当 耗时的. 内核对象(进程.线程.作业)要么处于触发态,要么处于未触发状态.进程内核对象在创建时总是处于未触发状态, 当进程终止时,操作系统会自动使进程内核对象变成触发状态.当进程内核对象处于触发状态后,将永远保持这种状态, 再也不能变回未触发状态. 2.等待内核对象 WaitForSingleObject等待单个内核对象,WaitForMultipleO

Windows核心编程笔记(2)

6 进程实例句柄 6.1 每一个EXE或者DLL被加载到内存中后,都会被赋予一个独一无二的句柄(HINSTANCE),该句柄在WinMain函数调用时传入.获取应用程序相关信息(资源.路径)时,有的需要传入HINSTANC有的需要传入HMODULE,实际上HINSTANC与HMODULE完全是一回事,这是16位Windows系统上不同数据类型造成的. WinMain函数的第一个参数:实例句柄是如何传递进来的呢?查看crtexe.c源码,我们会看到如下代码 #ifdef WPRFLAG mainr

Windows核心编程笔记(6)----用户模式下的线程同步

1.原子锁 使用InterlockedExchangeAdd函数来实现原子增长,InterlockedExchange\InterlockedExchangePointer用来交换两个变 量的值,InterlockedCompareExchange对比数值,相等则交换(对应的InterlockedCompareExchangePointer).对应的 还有64位函数. InterlockedIncrement\InterlockedDecrement是比较老的函数,只能增加或递减1,Interl

Windows核心编程笔记(5)----线程调度,优先级

1.操作系统线程调度过程 每个线程都有一个上下文CONTEXT结构体,保存在线程的内核对象中,这个上下文中保存了线程上一次执行时CPU寄存器 的状态.每隔固定时间,Windows会查看所有当前存在的线程内核对象,其中只有一些是可调度的.Windows在可调度的 线程中选择一个,并将上次保存到线程上下文中的数据载入CPU寄存器中.(上下文切换) CPU时间片到后,Windows移出这个线程,把CPU寄存器信息保存到线程上下文中,切换到另一个线程,如此循环. 2.线程的挂起和恢复 调用CreateP

Windows核心编程笔记(4)----线程

1.进程与线程 进程是惰性的,从来不执行任何东西,它只是一个线程的容器.线程必定是在某个进程的上下文中创建的, 而且其生命周期都在该进程中.因为句柄表是针对每一个进程的,因此同一个进程中的多个线程可以共享 内核对象句柄.进程运行需要占用许多的内存资源(加载DLL等),进程只需要一个内核对象和一个进程栈, 无需占用多少内存. 2.终止线程的几种方式: 2.1线程函数返回(强烈推荐) 2.2通过ExitThread函数杀死自己(自杀,不推荐) 终止线程运行,操作系统清理线程使用的系统资源,但是C/C

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

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

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

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

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实际机制可能有出入,但应该是合理的.开头几章由于我追求简洁