作业 -> 【Windows核心编程(第五版)】

版权声明:本文为博主原创文章,未经博主 请随意转载!! https://blog.csdn.net/VonSdite/article/details/81875853

作业

Windows提供了一个作业内核对象, 允许我们将进程组合在一起并创建一个“沙箱”来限制进程能做什么.

// 验证进程是否在一个作业控制下运行
BOOL IsProcessInJob(HANDLE hProcess, HANDLE hJob, PBOOL pbInJob);
  • 默认下,用资源管理器启动一个应用,进程自动与一个专用作业关联
  • 如为应用程序定义了一个清单,Windows资源管理器不会将我们的进程同专用作业关联。调试应用时,应用会从调试器继承专用作业。
  • 如果用命令行启动调试,调试器不会与专用作业关联,调试的应用也不会。
// 创建作业内核对象
HANDLE CreateJobObject(
DWORD dwDesiredAccess, 
BOOL bInheritHandle, 
PCTSTR pszName);

// 打开现有作业对象
HANDLE OpenJobObject(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName
);

// 关闭作业对象,表示不再访问此对象。
// 作业对象在作业中所有进程都已终止运行后,才自动销毁
CloseHandle(HANDLE hWndJob);

// 把进程分配给作业
BOOL AssignProcessToJobObject(HANDLE hJob, HANDLE hProcess);

对作业中进程施加限制

  1. 基本限额和扩展基本限额
  2. 基本的UI限制
  3. 安全限额
BOOL SetInformationJobObject(
HANDLE hJob, 
JOBOBJECTINFOCLASS JobObjectInformationClass, 
PVOID pJobObjectInformation, 
DWORD cbJobObjectInformationSize);

typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION
{
// 用户模式时间限制--针对进程
LARGE_INTEGER PerProcessUserTimeLimit;
// 用户模式时间限制--针对作业
LARGE_INTEGER PreJobUserTimeLimit;
// 标识有效字段
DWORD LimitFlags;
DWORD MinimumWorkingSetSize;
DWORD MaximumWorkingSetSize;
DWORD ActiveProcessLimit;
DWORD_PTR Affinity;
// 作业的优先级类
DWORD PriorityClass;
// 同一优先级类的作业的相对优先级
DWORD SchedulingClass;
};

typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
IO_COUNTERS IoInfo;
SIZE_T ProcessMemoryLimit;
SIZE_T JobMemoryLimit;
SIZE_T PeakProcessMemoryUsed;
SIZE_T PeakJobMemoryUsed;
};

typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS
{
// JOB_OBJECT_UI_LIMIT_HANDLES 不可使用作业外进程的用户对象句柄
// ...
DWORD UIRestrictionsClass;
};

BOOL UserHandleGrantAccess(
// 用户对象
HANDLE hUserObj,
HANDLE hJob,
BOOL bGrant
);

typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION
{
DWORD SecurityLimitFlags;
// 作业令牌
HANDLE JobToken;
PTOKEN_GROUPS SidsToDisable;
PTOKEN_PRIVILEGES PrivilegesToDelete;
PTOKEN_GROUPS RestrictedSids;
};

将进程放入作业

// 一旦进程已属作业的一部分,就不能再移动到另一个作业或从作业中移除
BOOL AssignProcessToJobObject(
HANDLE hJob,
HANDLE hProcess
);

// 作业中进程生成的进程默认也在作业中
// 作业基础限额有标志,JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK新进程不属于作业
// 有标志,JOB_OBJECT_LIMIT_BREAKAWAY_OK,CreateProcess时要指定CREATE_BREAKAWAY_FROM_JOB才可

杀死作业内所有进程

BOOL TerminateJobObject(
HANDLE hJob,
UINT uExitCode
);

查询作业信息

// 4类限额信息
// 统计信息
// 作业内进程列表
// JobObjectBasicAccountingInformation
// JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
BOOL QueryInformationJobObject(
HANDLE hJob,
JOBOBJECTINFOCLASS JobObjectInformationClass,
PVOID pvJobObjectInformation,
DWORD cbJobObjectInformationSize,
PDWORD pdwReturnSize
);

typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
{
LARGE_INTEGER TotalUserTime;
LARGE_INTEGER TotalKernelTime;
LARGE_INTEGER ThisPeriodTotalUserTime;
LARGE_INTEGER ThisPeriodTotalKernelTime;
DWORD TotalPageFaultCount;
DWORD TotalProcess;
DWORD TotalTerminatedProcesses;
};

typedef struct JOBOBJECT_BASIC_AND_IO_COUNTING_INFORMATION
{
JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;
IO_COUNTERS IoInfo;
};

typedef struct _IO_COUNTERS
{
ULONGLONG ReadOperationCount;
ULONGLONG WriteOperationCount;
ULONGLONG OtherOperationCount;
ULONGLONG ReadTransferCount;
ULONGLONG WriteTransferCount;
ULONGLONG OtherTransferCount;
};

// 对不属于作业的进程
BOOL GetProcessIoCounters(
HANDLE hProcess,
PIO_COUNTERS pIoCounters
);

// JobObjectBasicProcessIdList
// JOBOBJECT_BASIC_PROCESS_ID_LIST

typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST(
// 传入(要保证足够大)
DWORD NumberOfAssignedProcesses;
// 传出
DWORD NumberOfProcessIdsInList;
// 数组首地址
DWORD ProcessIdList[1];
);

作业通知

作业用完所有已分配的CPU时间,就会强行“杀死”作业中的所有进程并触发作业对象。
之后,还可用SetInformationJobObject把作业对象重置为未触发状态。
1. 创建一个I/O完成端口。
2. 将我们的作业对象与完成端口关联。
3. 须有一个或多个线程等待作业通知到达完成端口。

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

// 线程监视完成端口
BOOL GetQueuedCompletionStatus(
HANDLE hIOCP,
PDWORD pNumBytesTransferred,
// 区分作业
PULONG_PTR pCompletionKey,
POVERLAPPED *pOverlapped,
DWORD dwMilliseconds
);

默认下,分配给作业的CPU时间到期,它的所有进程都自动终止,且不投递 JOB_OBJECT_MSG_END_OF_JOB_TIME

JOBOBJECT_END_OF_JOB_TIME_INFORMATION joeojti;
// JOB_OBJECT_TERMINATE_AT_END_OF_JOB 默认值
// JOB_OBJECT_POST_AT_END_OF_JOB
joeojti.EndOfJobTimeAction = xx;
SetInformationJobObject(hJob, JobObjectEndOfJobTimeInformation,
&joeojti,
sizeof(joeojti));

猜你喜欢

转载自blog.csdn.net/VonSdite/article/details/81875853