Windows via C/C++ 学习(13)作业
时间:2011-01-30 来源:nrj
如果一个进程与一个作业相关,没有办法将个进程和进程的所有子进程脱离这个作业,可以使用 IsProcessInJob 来获取它是否与某个进程关联。
默认情况下,当你从 Windows Explorer 中启动一个应用程序时,这个进程会自动与一个作业关联,这个作业的名称有“PCA”前缀。所以当你调试你的应用程序时,如果调试器从 Windows Explorer 启动,你的应用程序总是与“PCA”作业相关,因为应用程序的父进程是调试器。如果调试器从命令行启动,就不会发生这种情况,它不与任何作业关联。如果你从 Windows Explorer 或从命令行启动包含以下代码的程序,会有不同的结果:
BOOL fIsInJob; IsProcessInJob(GetCurrentProcess(), NULL, &fIsInJob); if(fIsInJob) MessageBox(NULL, TEXT("进程已在作业中"), TEXT(""), MB_ICONINFORMATION|MB_OK);
同其它内核对象一样,你可以使用 CreateJobObject 来创建一个作业内核对象,使用 OpenJobObject 来打开一个命名作业内核对象,最后使用 CloseHandle 来关闭内核对象,注意,关闭一个作业内核对象不会终止与作业关联的进程的运行,它只是变为不可访问,作业内核对象会一直存在,直到所有进程终止为止。
限制作业的进程
作业有三种不同类型的限制:
1. 基本限制和扩展的基本限制避免作业中的进程独占系统资源;2. 基本 UI 限制避免作业中的进程修改用户界面;3. 安全限制避免作业中的进程访问安全资源。
可以使用
BOOL SetInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, PVOID pJobObjectInformation, DWORD cbJobObjectInformationSize);
来设置一个作业的限制。
如果设置一个基本 UI 限制时指定了 JOB_OBJECT_UILIMIT_HANDLES 标志,那么作业内所有的进程都不会访问到作业外所有进程的用户对象,也不能向作业外的进程窗口发送(Send 或 Post)窗口消息,但用户可以使用
BOOL UserHandleGrantAccess( HANDLE hUserObj, HANDLE hJob, BOOL bGrant);
打破这个限制,hUserObj 表示你要授与或禁止访问的用户控件句柄,hJob 表示要授与或禁止访问的作业句柄,如果调用是从与 hJob 表示的作业内的进程发出的,这个函数会失败,因为不允许一个进程为自己所在作业取得一个作业外用户对象的访问权。
用户可以使用
BOOL QueryInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, PVOID pvJobObjectInformation, DWORD cbJobObjectInformationSize, PDWORD pdwReturnSize);
查询一个作业某种类型的所有限制,hJob 为 NULL,表示要查询当前进程所在作业。
将进程与作业关联
如果要想将一个进程与作业关联,创建新进程时应传递一个 CREATE_SUSPENDED 标志,这样新进程不会立即运行,否则,在新进程被加入到作业之前,进程可能已经做了需要作业限制的工作。
要将一个进程加入到作业,使用
BOOL AssignProcessToJobObject( HANDLE hJob, HANDLE hProcess);
加入到作业的进程必须不与任何作业关联,进程与某个作业关联后不可再取消关联。加入到作业的进程的子进程默认也加入到这个作业,如果要想子进程不与作业发生关联,可以使用以下两种方法:
1. 创建一个作业时,在 JOBOBJECT_BASIC_LIMIT_INFORMATION 的 LimitFlags 成员中打开 JOB_OBJECT_LIMIT_BREAKAWY_OK 标志,同时,CreateProcess 函数中使用 CREATE_BREAKEWAY_FROM_JOB 标志。如果作业没有打开 JOB_OBJECT_LIMIT_BREAKAWY_OK 标志,中使用 CREATE_BREAKEWAY_FROM_JOB 标志的 CreateProcess 函数会失败,避免新进程控制作业的行为;
2. 创建一个作业时,在 JOBOBJECT_BASIC_LIMIT_INFORMATION 的 LimitFlags 成员中打开 JOB_OBJECT_LIMIT_SILENT_BREAKAWY_OK 标志,这样作业中的进程创建子进程时,默认不会与作业关联。
终止作业内的所有进程
可以调用
BOOL TerminateJobObject( HANDLE hJob, UINT uExitCode);
来终止进程内所有进程,这类似于进程中每一个进程中都分别调用 TerminateProcess,并设置退出代码为 uExitCode。