首页 > 系统相关 >windows 核心编程 - windows作业限制设置

windows 核心编程 - windows作业限制设置

时间:2024-08-26 20:52:57浏览次数:13  
标签:OBJECT joeli windows hwnd 编程 作业 BasicLimitInformation JOB IDC

演示作业限制设置

演示作业限制设置

文章目录


演示作业限制设置


/*
演示作业限制设置
*/

#include"..\\CommonFiles\\CmnHdr.h"
#include "resource.h"

#include "Job.h"
#include<tchar.h>
#include<strsafe.h>
#include<windowsx.h>



HWND g_hwnd;				//对话框句柄(被所有的线程访问)
HANDLE g_hIOCP;				//用来接受作业通知完成的端口
HANDLE g_hThreadIOCP;		//完成端口线程句柄
CJob g_job;					//作业对象句柄


//完成端口的CompletionKey 
#define COMPKEY_TERMINATE	((UINT_PTR)0)
#define COMPKEY_STATUS		((UINT_PTR)1)
#define COMPKEY_JOBOBJECT	((UINT_PTR)2)


void GetProcessName(DWORD PID, PTSTR szProcessName, size_t cchSize) {
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
	if (hProcess ==NULL)
	{
		_tcscpy_s(szProcessName, cchSize, TEXT("???"));
		return;
	}
	//....
	//以上函数调用,可用下列函数来替代,因为下列函数可适用各种情况
	DWORD dwSize = (DWORD)cchSize;
	QueryFullProcessImageName(hProcess, 0, szProcessName, &dwSize);
	CloseHandle(hProcess);
}


DWORD WINAPI JobNotify(PVOID) {
	TCHAR sz[3000];
	BOOL fDone = FALSE;
	ULONG_PTR CompKey;//指定出发这个事件的作业对象的句柄
	LPOVERLAPPED po;//进程ID
	DWORD dwBytesXferred;//等待的事件ID

	while (!fDone)
	{
		GetQueuedCompletionStatus(g_hIOCP, &dwBytesXferred, 
			&CompKey, &po, INFINITE);
		

		//应用程序关闭,退出线程
		fDone = (CompKey == COMPKEY_TERMINATE);

		//lpClassName为NULL则查找所有标题与第二个参数匹配的窗口
		HWND hwndLB = FindWindow(NULL, TEXT("Job Lab"));
		hwndLB = GetDlgItem(hwndLB, IDC_STATUS);

		if (CompKey == COMPKEY_JOBOBJECT)
		{
			_tcscpy_s(sz, _countof(sz), TEXT("--> Notification:"));
			PTSTR psz = sz + _tcslen(sz);
			switch (dwBytesXferred)
			{
			 //作业对象中活动进程数量达到上限
			case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("作业对象中活动进程数已达到上限!"));
				break;

				//作业对象中当前没有活动的进程
			case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("作业对象中当前没有活动进程"));
				break;

				//作业对象耗尽指定的时间片
			case JOB_OBJECT_MSG_END_OF_JOB_TIME: {
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("作业对象耗尽指定的时间片"));
				}
				break;
				//作业对象耗尽指定的内存
			case JOB_OBJECT_MSG_JOB_MEMORY_LIMIT: {
				TCHAR szProcessName[MAX_PATH];
				GetProcessName(PtrToUlong(po), szProcessName, MAX_PATH);//po存在进程ID
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("进程 %s(ID=%d)导致作业对象消耗内存到达到上限!"),szProcessName,po);
				}
												break;
												//新进程加入作业对象
			case JOB_OBJECT_MSG_NEW_PROCESS: {
				TCHAR szProcessName[MAX_PATH];
				GetProcessName(PtrToUlong(po), szProcessName, MAX_PATH);
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("进程 %s(ID=%d)加入作业对象!"), szProcessName, po);

			}
										   break;

										   //进程正常退出
			case JOB_OBJECT_MSG_EXIT_PROCESS: {
				TCHAR szProcessName[MAX_PATH];
				DWORD dwExitCode = 0;
				//注意进程退出了。但其内核对象并没有释放,还可以从内核对象中获取推出吗
				HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PtrToUlong(po));
				if (NULL != hProcess)
				{
					GetExitCodeProcess(hProcess, &dwExitCode);
					CloseHandle(hProcess);
				}
				GetProcessName(PtrToUlong(po), szProcessName, MAX_PATH);//po存在进程ID
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("进程 %s(ID=%d)正常退出,推出码(%d)!"), szProcessName, po, dwExitCode);
			}
											break;
											

											//进程异常退出
			case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
				TCHAR szProcessName[MAX_PATH];
				DWORD dwExitCode = 0;
				//注意进程退出了。但其内核对象并没有释放,还可以从内核对象中获取推出吗
				HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PtrToUlong(po));
				if (NULL != hProcess)
				{
					GetExitCodeProcess(hProcess, &dwExitCode);
					CloseHandle(hProcess);
				}
				GetProcessName(PtrToUlong(po), szProcessName, MAX_PATH);//po存在进程ID
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("进程 %s(ID=%d)异常退出,推出码(%d)!"), szProcessName, po, dwExitCode);
			}
													 break;

													 //进程耗尽时间片
			case JOB_OBJECT_MSG_END_OF_PROCESS_TIME: {
				TCHAR szProcessName[MAX_PATH];
				GetProcessName(PtrToUlong(po), szProcessName, MAX_PATH);
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("进程%s(ID-%d)耗尽事件片!"), szProcessName, po);
			}
												   break;

												   //进程小号内存数量达到上限
			case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
				TCHAR szProcessName[MAX_PATH];
				GetProcessName(PtrToUlong(po), szProcessName, MAX_PATH);
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("进程%s(ID=%d)小号内存达到上限!"), szProcessName, po);
			}
													break;
			default:
				StringCchPrintf(psz, _countof(sz) - _tcslen(sz),
					TEXT("未知通知:%d"), dwBytesXferred);
			}
			ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
			CompKey = 1;//当作业通知到达时,强迫更新状态
		}

		//更新作业状态
		if (CompKey == COMPKEY_STATUS)
		{
			static int s_nStatusCount = 0;
			StringCchPrintf(sz, _countof(sz),
				TEXT("-->状态更新(%u)"), s_nStatusCount++);
			ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));

			//显示作业对象的基本统计信息
			JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION jobai;
			g_job.QueryBasicAccountingInfo(&jobai);

			StringCchPrintf(sz, _countof(sz),
				TEXT("总时间:用户=%I64u,内核=%I64u    ")
				TEXT("Period时间:用户=%I64u,内核=%I64u"),
				jobai.BasicInfo.TotalUserTime.QuadPart,
				jobai.BasicInfo.TotalKernelTime.QuadPart);
			ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));

			StringCchPrintf(sz, _countof(sz),
				TEXT("页面错误=%u,总进程数=%u,   ")
				TEXT("活动进程数=%u,已终止的进程数=%u"),
				jobai.BasicInfo.TotalPageFaultCount,
				jobai.BasicInfo.TotalProcesses,
				jobai.BasicInfo.ActiveProcesses,
				jobai.BasicInfo.TotalTerminatedProcesses);

			//显示IO统计信息
			StringCchPrintf(sz, _countof(sz),
				TEXT("读取=%I64u(i64u byte),   ")
				TEXT("写入=%I64u(i64u byte),其他=%I64u(I64u bytes"),
				jobai.IoInfo.ReadOperationCount, jobai.IoInfo.ReadTransferCount,
				jobai.IoInfo.WriteOperationCount, jobai.IoInfo.WriteTransferCount,
				jobai.IoInfo.OtherOperationCount, jobai.IoInfo.OtherTransferCount
			);
			ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));

			//显示每个进程和作业的内存峰值
			JOBOBJECT_EXTENDED_LIMIT_INFORMATION joeli;
			g_job.QueryExtendedLimitInfo(&joeli);
			StringCchPrintf(sz,_countof(sz),
				TEXT("已使用内存峰值:进程=%I64u,作业=%I64u"),
				(__int64)joeli.PeakProcessMemoryUsed,
				(__int64)joeli.PeakJobMemoryUsed);
			ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));

			//显示进程ID集
			const int iNum = 50;
			DWORD dwNumProcess = iNum;
			DWORD dwProcessIDList[iNum];
			g_job.QueryBasicProcessIdList(dwNumProcess, dwProcessIDList, &dwNumProcess);
			StringCchPrintf(sz, _countof(sz), TEXT("进程ID集:%s"),
				(dwNumProcess == 0) ? TEXT("none") : TEXT(""));
			ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));

			TCHAR szProcessName[MAX_PATH];
			for (DWORD x = 0; x < dwNumProcess; x++)
			{
				GetProcessName(dwProcessIDList[x], szProcessName, _countof(szProcessName));
				StringCchPrintf(sz, _countof(sz), TEXT("    %d - %s"),
					dwProcessIDList[x], szProcessName);
				ListBox_SetCurSel(hwndLB, ListBox_AddString(hwndLB, sz));
			}
				
		}
	}
	return 0;
}

void Dlg_ApplayLimits(HWND hwnd) {
	const int nNanosecondsPerSecond = 1000000000;//1s=1000ms,1ms=1000us,1us=1000ns
	const int nMillisecondsPerSecond = 1000;//1s=1000ms
	const int nNanosecondsPerMillisecond =
		nNanosecondsPerSecond / nMillisecondsPerSecond;

	__int64 q;
	SIZE_T s;
	DWORD d;
	BOOL f;

	//设置作业的基本\扩展限制
	JOBOBJECT_EXTENDED_LIMIT_INFORMATION joeli = {};
	joeli.BasicLimitInformation.LimitFlags = 0;

	//进程用户模式时间限制-f指出转换是否成功
	q = GetDlgItemInt(hwnd, IDC_PERPROCESSUSERTIMELIMIT, &f, FALSE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME;
		joeli.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart =
			q * nNanosecondsPerMillisecond / 100;//ns/ms

	}

	//作业用户模式时间限制-f住处转换是否成功
	q = GetDlgItemInt(hwnd, IDC_PERJOBUSERTIMELIMIT, &f, FALSE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_TIME;
		joeli.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart =
			q * nNanosecondsPerMillisecond / 100;//ns/ms
	}

	//最小工作集
	s = GetDlgItemInt(hwnd, IDC_MINWORKINGSETSIZE, &f, FALSE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
		joeli.BasicLimitInformation.MinimumWorkingSetSize = s * 1024 * 1025;
		s = GetDlgItemInt(hwnd, IDC_MAXWORKINGSETSIZE, &f, FALSE);
		if (f)
		{
			joeli.BasicLimitInformation.MaximumWorkingSetSize = s * 1024 * 1024;
		}
		else
		{
			joeli.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_WORKINGSET;
			MessageBox(hwnd, TEXT("最小和最大工作集同时设置。\n"), NULL, MB_OK | MB_OKCANCEL);

		}
	}

	//最大同时活动进程数
	d = GetDlgItemInt(hwnd, IDC_ACTIVEPROCESSLIMIT, &f, TRUE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
		joeli.BasicLimitInformation.ActiveProcessLimit = d;
	}
	//进程亲缘性掩码:进程和线程的亲缘性(affinity)是指可以将进程或者是线程强制限制在可用的CPU子集上运行的特性
	//使与作业关联的所有进程使用相同的处理器亲缘关系。Affinity成员包含附加信息 。
	// 如果作业是嵌套的,则指定的处理器亲和性必须是父作业的有效亲和性的子集。
	//如果指定的亲和性是父作业的亲和性的超集,则忽略它并使用父作业的亲和性。
	s = GetDlgItemInt(hwnd, IDC_AFFINITYMASK, &f, FALSE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_AFFINITY;
		joeli.BasicLimitInformation.ActiveProcessLimit = s;
	}
	//作业优先级
	joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
	switch (ComboBox_GetCurSel(GetDlgItem(hwnd,IDC_PRIORITYCLASS)))
	{
	case 0:
		joeli.BasicLimitInformation.LimitFlags &=
			~JOB_OBJECT_LIMIT_PRIORITY_CLASS;
		break;
	case 1:
		joeli.BasicLimitInformation.PriorityClass =
			IDLE_PRIORITY_CLASS;
		break;
	case 2:
		joeli.BasicLimitInformation.PriorityClass =
			BELOW_NORMAL_PRIORITY_CLASS;
		break;
	case 3:
		joeli.BasicLimitInformation.PriorityClass =
			NORMAL_PRIORITY_CLASS;
		break;
	case 4:
		joeli.BasicLimitInformation.PriorityClass =
			ABOVE_NORMAL_PRIORITY_CLASS;
		break;
	case 5:
		joeli.BasicLimitInformation.PriorityClass =
			HIGH_PRIORITY_CLASS;
		break;
	case 6:
		joeli.BasicLimitInformation.PriorityClass =
			REALTIME_PRIORITY_CLASS;
		break;
	}

	//SchedulingClass

	int nSchedulingClass =
		ComboBox_GetCurSel(GetDlgItem(hwnd, IDC_SCHEDULINGCLASS));
	if (nSchedulingClass > 0)
	{
		joeli.BasicLimitInformation.LimitFlags |= 
			JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
		joeli.BasicLimitInformation.SchedulingClass = nSchedulingClass - 1;
	}

	//作业提交的最大物理页面
	s = GetDlgItemInt(hwnd, IDC_MAXCOMMITPERJOB, &f, FALSE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
		joeli.JobMemoryLimit = s * 1024 * 1024;
	}

	//进程的提交最大物理页面
	s = GetDlgItemInt(hwnd, IDC_MAXCOMMITPERPROCESS, &f, FALSE);
	if (f)
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
		joeli.JobMemoryLimit = s * 1024 * 1024;
	}

	if (IsDlgButtonChecked(hwnd,IDC_CHILDPROCESSESCANBREAKAWAYFROMJOB))
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
	}

	if (IsDlgButtonChecked(hwnd, IDC_CHILDPROCESSESDOBREAKAWAYFROMJOB))
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
	}

	if (IsDlgButtonChecked(hwnd, IDC_TERMINATEPROCESSONEXCEPTIONS))
	{
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
	}

	f = g_job.SetExtendedLimitInfo(&joeli,
		((joeli.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME)
			!= 0) ? FALSE :
		IsDlgButtonChecked(hwnd, IDC_PRESERVEJOBTIMEWHENAPPLYINGLIMITS));

	chASSERT(f);//调试版,f弹对话框

	//设置UI限制
	DWORD jobuir = JOB_OBJECT_UILIMIT_NONE;//0;
	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTACCESSTOOUTSIDEUSEROBJECTS))
		jobuir |= JOB_OBJECT_UILIMIT_HANDLES;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTREADINGCLIPBOARD))
		jobuir |= JOB_OBJECT_UILIMIT_READCLIPBOARD;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTWRITINGCLIPBOARD))
		jobuir |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTEXITWINDOW))
		jobuir |= JOB_OBJECT_UILIMIT_EXITWINDOWS;


	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTCHANGINGSYSTEMPARAMETERS))
		jobuir |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTDESKTOPS))
		jobuir |= JOB_OBJECT_UILIMIT_DESKTOP;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTDISPLAYSETTINGS))
		jobuir |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTGLOBALATOMS))
		jobuir |= JOB_OBJECT_UILIMIT_GLOBALATOMS;

	chVERIFY(g_job.SetBasicUIRestrictions(jobuir));
}

//
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndfocus, LPARAM lParam)
{
	chSETDLGICONS(hwnd, IDI_JOBLAB);
	//保存窗口句柄,以便在完成端口线程中可以访问到
	g_hwnd = hwnd;

	HWND hwndPriorityClass = GetDlgItem(hwnd, IDC_PRIORITYCLASS);
	ComboBox_AddString(hwndPriorityClass, TEXT("No limit"));
	ComboBox_AddString(hwndPriorityClass, TEXT("Idle"));
	ComboBox_AddString(hwndPriorityClass, TEXT("Below normal"));
	ComboBox_AddString(hwndPriorityClass, TEXT("Normal"));
	ComboBox_AddString(hwndPriorityClass, TEXT("Above normal"));
	ComboBox_AddString(hwndPriorityClass, TEXT("High"));
	ComboBox_AddString(hwndPriorityClass, TEXT("Realtime"));
	ComboBox_SetCurSel(hwndPriorityClass, 0); // Default to "No Limit"

	HWND hwndSchedulingClass = GetDlgItem(hwnd, IDC_SCHEDULINGCLASS);
	ComboBox_AddString(hwndSchedulingClass, TEXT("No limit"));
	for (int n = 0; n <= 9; n++) {
		TCHAR szSchedulingClass[2];
		StringCchPrintf(szSchedulingClass, _countof(szSchedulingClass),
			TEXT("%u"), n);
		ComboBox_AddString(hwndSchedulingClass, szSchedulingClass);
	}
	ComboBox_SetCurSel(hwndSchedulingClass, 0); // Default to "No Limit"
	SetTimer(hwnd, 1, 10000, NULL);             // 10 second accounting update
	return(TRUE);
}
///


void Dlg_ApplyLimits(HWND hwnd) {
	const int nNanosecondsPerSecond = 1000000000;
	const int nMillisecondsPerSecond = 1000;
	const int nNanosecondsPerMillisecond =
		nNanosecondsPerSecond / nMillisecondsPerSecond;
	BOOL f;
	__int64 q;
	SIZE_T s;
	DWORD d;

	// Set Basic and Extended Limits
	JOBOBJECT_EXTENDED_LIMIT_INFORMATION joeli = { 0 };
	joeli.BasicLimitInformation.LimitFlags = 0;

	q = GetDlgItemInt(hwnd, IDC_PERPROCESSUSERTIMELIMIT, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME;
		joeli.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart =
			q * nNanosecondsPerMillisecond / 100;
	}

	q = GetDlgItemInt(hwnd, IDC_PERJOBUSERTIMELIMIT, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_TIME;
		joeli.BasicLimitInformation.PerJobUserTimeLimit.QuadPart =
			q * nNanosecondsPerMillisecond / 100;
	}

	s = GetDlgItemInt(hwnd, IDC_MINWORKINGSETSIZE, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
		joeli.BasicLimitInformation.MinimumWorkingSetSize = s * 1024 * 1024;
		s = GetDlgItemInt(hwnd, IDC_MAXWORKINGSETSIZE, &f, FALSE);
		if (f) {
			joeli.BasicLimitInformation.MaximumWorkingSetSize = s * 1024 * 1024;
		}
		else {
			joeli.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_WORKINGSET;
			chMB("Both minimum and maximum working set sizes must be set.\n"
				"The working set limits will NOT be in effect.");
		}
	}

	d = GetDlgItemInt(hwnd, IDC_ACTIVEPROCESSLIMIT, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |=
			JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
		joeli.BasicLimitInformation.ActiveProcessLimit = d;
	}

	s = GetDlgItemInt(hwnd, IDC_AFFINITYMASK, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_AFFINITY;
		joeli.BasicLimitInformation.Affinity = s;
	}

	joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
	switch (ComboBox_GetCurSel(GetDlgItem(hwnd, IDC_PRIORITYCLASS))) {
	case 0:
		joeli.BasicLimitInformation.LimitFlags &=
			~JOB_OBJECT_LIMIT_PRIORITY_CLASS;
		break;

	case 1:
		joeli.BasicLimitInformation.PriorityClass =
			IDLE_PRIORITY_CLASS;
		break;

	case 2:
		joeli.BasicLimitInformation.PriorityClass =
			BELOW_NORMAL_PRIORITY_CLASS;
		break;

	case 3:
		joeli.BasicLimitInformation.PriorityClass =
			NORMAL_PRIORITY_CLASS;
		break;

	case 4:
		joeli.BasicLimitInformation.PriorityClass =
			ABOVE_NORMAL_PRIORITY_CLASS;
		break;

	case 5:
		joeli.BasicLimitInformation.PriorityClass =
			HIGH_PRIORITY_CLASS;
		break;

	case 6:
		joeli.BasicLimitInformation.PriorityClass =
			REALTIME_PRIORITY_CLASS;
		break;
	}

	int nSchedulingClass =
		ComboBox_GetCurSel(GetDlgItem(hwnd, IDC_SCHEDULINGCLASS));
	if (nSchedulingClass > 0) {
		joeli.BasicLimitInformation.LimitFlags |=
			JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
		joeli.BasicLimitInformation.SchedulingClass = nSchedulingClass - 1;
	}

	s = GetDlgItemInt(hwnd, IDC_MAXCOMMITPERJOB, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
		joeli.JobMemoryLimit = s * 1024 * 1024;
	}

	s = GetDlgItemInt(hwnd, IDC_MAXCOMMITPERPROCESS, &f, FALSE);
	if (f) {
		joeli.BasicLimitInformation.LimitFlags |=
			JOB_OBJECT_LIMIT_PROCESS_MEMORY;
		joeli.ProcessMemoryLimit = s * 1024 * 1024;
	}

	if (IsDlgButtonChecked(hwnd, IDC_CHILDPROCESSESCANBREAKAWAYFROMJOB))
		joeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;

	if (IsDlgButtonChecked(hwnd, IDC_CHILDPROCESSESDOBREAKAWAYFROMJOB))
		joeli.BasicLimitInformation.LimitFlags |=
		JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;

	if (IsDlgButtonChecked(hwnd, IDC_TERMINATEPROCESSONEXCEPTIONS))
		joeli.BasicLimitInformation.LimitFlags |=
		JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;

	f = g_job.SetExtendedLimitInfo(&joeli,
		((joeli.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME)
			!= 0) ? FALSE :
		IsDlgButtonChecked(hwnd, IDC_PRESERVEJOBTIMEWHENAPPLYINGLIMITS));
	chASSERT(f);

	// Set UI Restrictions
	DWORD jobuir = JOB_OBJECT_UILIMIT_NONE;  // A fancy zero (0)
	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTACCESSTOOUTSIDEUSEROBJECTS))
		jobuir |= JOB_OBJECT_UILIMIT_HANDLES;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTREADINGCLIPBOARD))
		jobuir |= JOB_OBJECT_UILIMIT_READCLIPBOARD;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTWRITINGCLIPBOARD))
		jobuir |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTEXITWINDOW))
		jobuir |= JOB_OBJECT_UILIMIT_EXITWINDOWS;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTCHANGINGSYSTEMPARAMETERS))
		jobuir |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTDESKTOPS))
		jobuir |= JOB_OBJECT_UILIMIT_DESKTOP;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTDISPLAYSETTINGS))
		jobuir |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;

	if (IsDlgButtonChecked(hwnd, IDC_RESTRICTGLOBALATOMS))
		jobuir |= JOB_OBJECT_UILIMIT_GLOBALATOMS;

	chVERIFY(g_job.SetBasicUIRestrictions(jobuir));
}
///


void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {

	switch (id) {
	case IDCANCEL:
		// User is terminating our app, kill the job too.
		KillTimer(hwnd, 1);
		g_job.Terminate(0);
		EndDialog(hwnd, id);
		break;

	case IDC_PERJOBUSERTIMELIMIT:
	{
		// The job time must be reset if setting a job time limit
		BOOL f;
		GetDlgItemInt(hwnd, IDC_PERJOBUSERTIMELIMIT, &f, FALSE);
		EnableWindow(
			GetDlgItem(hwnd, IDC_PRESERVEJOBTIMEWHENAPPLYINGLIMITS), !f);
	}
	break;

	case IDC_APPLYLIMITS:
		Dlg_ApplyLimits(hwnd);
		PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_STATUS, NULL);
		break;

	case IDC_TERMINATE:
		g_job.Terminate(0);
		PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_STATUS, NULL);
		break;

	case IDC_SPAWNCMDINJOB:
	{
		// Spawn a command shell and place it in the job
		STARTUPINFO si = { sizeof(si) };
		PROCESS_INFORMATION pi;
		TCHAR sz[] = TEXT("CMD");
		CreateProcess(NULL, sz, NULL, NULL,
			FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
		g_job.AssignProcess(pi.hProcess);
		ResumeThread(pi.hThread);
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
	PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_STATUS, NULL);
	break;

	case IDC_ASSIGNPROCESSTOJOB:
	{
		DWORD dwProcessId = GetDlgItemInt(hwnd, IDC_PROCESSID, NULL, FALSE);
		HANDLE hProcess = OpenProcess(
			PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, dwProcessId);
		if (hProcess != NULL) {
			chVERIFY(g_job.AssignProcess(hProcess));
			CloseHandle(hProcess);
		}
		else chMB("Could not assign process to job.");
	}
	PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_STATUS, NULL);
	break;
	}
}

///


void WINAPI Dlg_OnTimer(HWND hwnd, UINT id) {

	PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_STATUS, NULL);
}


///


INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

	switch (uMsg) {
		chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
		chHANDLE_DLGMSG(hwnd, WM_TIMER, Dlg_OnTimer);
		chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
	}

	return(FALSE);
}


///


int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {

	// Check if we are not already associated with a job.
	// If this is the case, 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(-1);
	}

	// Create the completion port that receives job notifications
	g_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

	// Create a thread that waits on the completion port
	g_hThreadIOCP = chBEGINTHREADEX(NULL, 0, JobNotify, NULL, 0, NULL);

	// Create the job object
	g_job.Create(NULL, TEXT("JobLab"));
	g_job.SetEndOfJobInfo(JOB_OBJECT_POST_AT_END_OF_JOB);
	g_job.AssociateCompletionPort(g_hIOCP, COMPKEY_JOBOBJECT);

	DialogBox(hinstExe, MAKEINTRESOURCE(IDD_JOBLAB), NULL, Dlg_Proc);

	// Post a special key that tells the completion port thread to terminate
	PostQueuedCompletionStatus(g_hIOCP, 0, COMPKEY_TERMINATE, NULL);

	// Wait for the completion port thread to terminate
	WaitForSingleObject(g_hThreadIOCP, INFINITE);

	// Clean up everything properly
	CloseHandle(g_hIOCP);
	CloseHandle(g_hThreadIOCP);

	// NOTE: The job is closed when the g_job's destructor is called.
	return(0);
}

moduel Job.h


/*
moduel Job.h
Notices:
*/

#pragma once
#include <malloc.h>	//for _alloca;
class CJob
{
private:
	HANDLE m_hJob;
public:
	CJob(HANDLE hJob = NULL);
	~CJob();
	operator HANDLE() const { return(m_hJob); }	//重载()运算符

	//用于打开或创建一个作业对象
	BOOL Create(PSECURITY_ATTRIBUTES psa = NULL, PCTSTR pszName = NULL);
	BOOL Open(PCTSTR pszName, DWORD dwDesiredAccess, BOOL fInheritHandle = FALSE);

	//用于操作作业对象的函数
	BOOL AssignProcess(HANDLE hProcess);
	BOOL Terminate(UINT uExitCode = 0);

	//用于设置或限制作业对象
	BOOL SetExtendedLimitInfo(PJOBOBJECT_EXTENDED_LIMIT_INFORMATION pjoeli, BOOL fPreserveJobTime = FALSE);
	BOOL SetBasicUIRestrictions(DWORD fdwLimits);
	BOOL GrantUserHandleAccess(HANDLE hUserOjb, BOOL fGrant = TRUE);//设置访问作业外用户对象能力
	BOOL SetSecurityLimitInfo(PJOBOBJECT_SECURITY_LIMIT_INFORMATION pjosli);

	//查询作业限制信息
	BOOL QueryExtendedLimitInfo(PJOBOBJECT_EXTENDED_LIMIT_INFORMATION pjoeli);
	BOOL QueryBasicUIRestrictions(PDWORD fdwRestrictions);
	BOOL QuerySecurityLimitInfo(PJOBOBJECT_SECURITY_LIMIT_INFORMATION pjosli);

	//查询作业状态信息
	BOOL QueryBasicAccountingInfo(PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION pjobai);
	BOOL QueryBasicProcessIdList(DWORD dwMaxProcess, PDWORD pdwProcessIdList,
		PDWORD pdwProcessesReturned = NULL);

	//设置或者查询作业的通知事件
	BOOL AssociateCompletionPort(HANDLE hIOCP, ULONG_PTR CompKey);
	BOOL QueryAssociatedCompletionPort(PJOBOBJECT_ASSOCIATE_COMPLETION_PORT pjoacp);
	BOOL SetEndOfJobInfo(DWORD fdwEndOfJobInfo = JOB_OBJECT_TERMINATE_AT_END_OF_JOB);
	BOOL QueryEndOfJobTimeInfo(PDWORD pfdwEndOfJobTimeInfo);
};

CJob::CJob(HANDLE hJob)
{
	m_hJob = hJob;
}

CJob::~CJob()
{
	if (NULL != m_hJob)
	{
		CloseHandle(m_hJob);
	}
}
///
inline BOOL CJob::Create(PSECURITY_ATTRIBUTES psa, PCTSTR pszName) {
	m_hJob = CreateJobObject(psa, pszName);
	return (m_hJob != NULL);
}

///
inline BOOL CJob::Open(PCTSTR pszName, DWORD dwDesiredAccess, BOOL fInheritHandle /*= FALSE*/) {
	m_hJob = OpenJobObject(dwDesiredAccess, fInheritHandle, pszName);
	return (m_hJob != NULL);
}

///
inline 	BOOL CJob::AssignProcess(HANDLE hProcess) {
	return(AssignProcessToJobObject(m_hJob, hProcess));
}

///
inline BOOL CJob::Terminate(UINT uExitCode /* = 0*/) {
	return(TerminateJobObject(m_hJob, uExitCode));
}

///
inline BOOL CJob::SetExtendedLimitInfo(
	PJOBOBJECT_EXTENDED_LIMIT_INFORMATION pjoeli, BOOL fPreserveJobTime /*= FALSE*/) {

	if (fPreserveJobTime)
	{
		pjoeli->BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME;
	}
	//如果要保留作业事件信息,则JOB_OBJECT_LIMIT_JOB_TIME标志必须去掉
	const DWORD fdwFlagTest =
		(JOB_OBJECT_LIMIT_JOB_TIME | JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME);

	if ((pjoeli->BasicLimitInformation.LimitFlags & fdwFlagTest) == fdwFlagTest);
	//DebugBreak();//这两个标志是互斥的,单现在两者同时被设置了。

	return (SetInformationJobObject(m_hJob, JobObjectExtendedLimitInformation,
		pjoeli, sizeof(*pjoeli)));
}

///
inline BOOL CJob::SetBasicUIRestrictions(DWORD fdwLimits) {
	JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir = { fdwLimits };
	return (SetInformationJobObject(m_hJob, JobObjectBasicUIRestrictions, &jobuir, sizeof(jobuir)));
}

///
inline BOOL CJob::GrantUserHandleAccess(HANDLE hUserOjb, BOOL fGrant /*= TRUE*/){
	return UserHandleGrantAccess(hUserOjb, m_hJob, fGrant);
}

///
inline BOOL CJob::SetSecurityLimitInfo(PJOBOBJECT_SECURITY_LIMIT_INFORMATION pjosli) {
	return (SetInformationJobObject(m_hJob,
		JobObjectSecurityLimitInformation, pjosli, sizeof(*pjosli)));
}

///
inline BOOL CJob::QueryExtendedLimitInfo(PJOBOBJECT_EXTENDED_LIMIT_INFORMATION pjoeli) {
	return (QueryInformationJobObject(m_hJob, JobObjectExtendedLimitInformation,
		pjoeli, sizeof(*pjoeli), NULL));
}

///
inline BOOL CJob::QueryBasicUIRestrictions(PDWORD fdwRestrictions) {
	JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir;
	BOOL fOk = QueryInformationJobObject(m_hJob, JobObjectBasicUIRestrictions,
		&jobuir, sizeof(jobuir), NULL);
	if (fOk)
	{
		*fdwRestrictions = jobuir.UIRestrictionsClass;
	}
	return (fOk);
}

///
inline BOOL CJob::QuerySecurityLimitInfo(PJOBOBJECT_SECURITY_LIMIT_INFORMATION pjosli) {
	return (QueryInformationJobObject(m_hJob, JobObjectSecurityLimitInformation,
		pjosli, sizeof(*pjosli), NULL));
}

 
inline BOOL CJob::QueryBasicAccountingInfo(PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION pjobai) {
	return (QueryInformationJobObject(m_hJob,
		JobObjectBasicAndIoAccountingInformation, pjobai, sizeof(*pjobai), NULL));
}

///
inline BOOL CJob::QueryBasicProcessIdList(DWORD dwMaxProcess, PDWORD pdwProcessIdList,
	PDWORD pdwProcessesReturned /*= NULL*/) {
	//计算所需的控件大小
	DWORD cb = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + (sizeof(DWORD) * (dwMaxProcess - 1));

	//从栈上分匹配内存(注意,不是堆,所有无需释放
	PJOBOBJECT_BASIC_PROCESS_ID_LIST  pjobpil =
		(PJOBOBJECT_BASIC_PROCESS_ID_LIST)_alloca(cb);


	BOOL fOk = (pjobpil != NULL);
	if (fOk)
	{
		//告知函数,我们分配的最大控件大小
		pjobpil->NumberOfProcessIdsInList = dwMaxProcess;

		//请求返回 当前进程集ID
		fOk = QueryInformationJobObject(m_hJob,
			JobObjectBasicProcessIdList, pjobpil, cb, NULL);
		if (fOk)
		{
			//得到信息,并返回给调用者
			if (pdwProcessesReturned != NULL)
			{
				*pdwProcessesReturned = pjobpil->NumberOfProcessIdsInList;

				CopyMemory(pdwProcessesReturned, pjobpil,
					sizeof(DWORD) * pjobpil->NumberOfProcessIdsInList);
			}
		}
	}
	return fOk;
}

///
inline BOOL CJob::AssociateCompletionPort(HANDLE hIOCP, ULONG_PTR CompKey) {
	JOBOBJECT_ASSOCIATE_COMPLETION_PORT joacp;
	joacp.CompletionPort = hIOCP;
	joacp.CompletionKey = (PVOID)CompKey;

	return(SetInformationJobObject(m_hJob,
		JobObjectAssociateCompletionPortInformation, &joacp, sizeof(joacp)));
}

///
inline BOOL CJob::QueryAssociatedCompletionPort(PJOBOBJECT_ASSOCIATE_COMPLETION_PORT pjoacp) {
	return (QueryInformationJobObject(m_hJob,
		JobObjectAssociateCompletionPortInformation, pjoacp, sizeof(*pjoacp), NULL));
}

///
inline BOOL CJob::SetEndOfJobInfo(DWORD fdwEndOfJobInfo /*= JOB_OBJECT_TERMINATE_AT_END_OF_JOB*/) {
	JOBOBJECT_END_OF_JOB_TIME_INFORMATION joeojti = { fdwEndOfJobInfo };
	return (SetInformationJobObject(m_hJob,
		JobObjectEndOfJobTimeInformation, &joeojti, sizeof(joeojti)));
}

///
inline BOOL CJob::QueryEndOfJobTimeInfo(PDWORD pfdwEndOfJobTimeInfo) {
	JOBOBJECT_END_OF_JOB_TIME_INFORMATION jobojti;
	BOOL fOk = QueryInformationJobObject(m_hJob,
		JobObjectEndOfJobTimeInformation, &jobojti, sizeof(jobojti), NULL);

	if (fOk)
	{
		*pfdwEndOfJobTimeInfo = jobojti.EndOfJobTimeAction;
	}
	return (fOk);
}

标签:OBJECT,joeli,windows,hwnd,编程,作业,BasicLimitInformation,JOB,IDC
From: https://blog.csdn.net/zhyjhacker/article/details/141573104

相关文章

  • 如何使用Kdrill检测Windows内核中潜在的rootkit
    关于KdrillKdrill是一款用于分析Windows64b系统内核空间安全的工具,该工具基于纯Python3开发,旨在帮助广大研究人员评估Windows内核是否受到了rootkit攻击。需要注意的是,该项目与Python2/3兼容,无其他依赖组件,无需Microsoft符号或网络连接即可执行安全检查。KDrill还......
  • 网络编程-Socket通信
    Socket通信1、什么是套接字​ Socket是封装了TCP/IP协议簇的系统API接口,这使得程序员无需关注协议本身,直接使用socket提供的接口与不同主机间的进程互联通信。​ 目前市面上主流的操作系统都采用这套机制进制网络通信,所以不同种类的操作系统,使用不同的编程语言,只要调用操作系统......
  • 【流式编程】Stream.of()用法解析及使用示例
    Stream.of()是Java8引入的StreamAPI中的一个静态方法,用于从给定的元素创建一个顺序流(SequentialStream)。这个方法非常灵活,允许你直接从一组元素中创建一个流,而不需要这些元素已经存在于某个集合或数组中。这对于快速创建和操作流非常有用。用法解析Stream.of()......
  • Python 多线程编程技巧举例
    Python多线程(Multithreading)是一种编程技术,允许在同一程序中同时执行多个独立的逻辑流,即线程。每个线程都有自己的程序计数器、栈空间和局部变量,它们共享同一进程的全局变量、文件描述符和其他系统资源。线程是操作系统调度的基本单位,能够在单个进程中并发运行,从而实现任务......
  • 大白话【8】WindowsServer2016搭建DNS服务
    1.DNS服务功能介绍2.DNS服务器搭建2.0准备环境2.1把该DNS服务器设置成静态IP2.2修改主机名(可省略)2.3安装DNS服务DNS服务器名为www;IP为192.168.2.1003.客户机测试在网内可网络连通的客户机如何验证DNS服务器域名解析有效性?3.1可以ping不通,只要看到解析就行。......
  • Windows恢复受阻?reagenttask.dll丢失的诊断与修复全流程
    reagenttask.dll是一个与Windows操作系统相关的动态链接库(DLL)文件,通常与Windows恢复环境(WindowsRecoveryEnvironment,RE)的功能实现有关。这个DLL文件可能包含了处理恢复环境内部逻辑、资源管理和与其他恢复组件交互等功能所需的函数和资源,对于确保Windows恢复环境的正常运......
  • 大白话【7】windows server2016共享目录配置
    1.windows权限模型案列共享目录搭建过程1.创建共享目录2.为人力资源部,销售部,IT部,等创建工作组3.创建用户关联用户组4.修改共享目录权限,允许xx工作组用户进入目录5.根据需求设置XX目录权限6.开启目录共享打开本地用户和组Win+R 输入lusrmgr.msc引申-普通用户想要使......
  • 24. 网络编程
    osi七层协议 每层常见物理设备 OSI(OpenSystemsInterconnection)七层协议是由国际标准化组织(ISO)制定的一个网络模型,它将网络系统划分为七个层次。以下是各层的详细解释: ‌物理层(PhysicalLayer)‌:这是OSI模型的最低层或第一层。它负责在物理媒体上传输原始的比特流......
  • java计算机毕业设计学生作业管理系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着教育信息化的不断深入,传统教学模式正逐步向数字化、智能化转型。在这一过程中,学生作业管理作为教学活动中的重要环节,其管理效率与质量直接影响到......
  • 【Win 10/Win 11】【Foxmail】解决Foxmail邮件客户端安装在Windows系统下Program File
    虽然到目前(2024/08)Foxmail邮件客户端已经有一段时间没有更新了,但它仍不失为Windows操作系统下好用的邮件客户端之一。笔者在安装Foxmail时将默认路径设置为了D:\ProgramFiles\,而Windows10和Windows11对于分区根目录下ProgramFiles,ProgramFile(x86)等文件夹有特殊的权限限制,......