/*
* Process Hacker -
* job handle
*
* Copyright (C) 2009 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Security;
namespace ProcessHacker.Native.Objects
{
///
/// Represents a handle to a Windows job object.
///
public class JobObjectHandle : Win32Handle
{
///
/// Creates a service handle using an existing handle.
/// The handle will not be closed automatically.
///
/// The handle value.
/// The job handle.
public static JobObjectHandle FromHandle(IntPtr handle)
{
return new JobObjectHandle(handle, false);
}
public static JobObjectHandle Create(string name)
{
IntPtr jobHandle = Win32.CreateJobObject(IntPtr.Zero, name);
if (jobHandle == IntPtr.Zero)
Win32.ThrowLastError();
return new JobObjectHandle(jobHandle, true);
}
private JobObjectHandle(IntPtr handle, bool owned)
: base(handle, owned)
{ }
///
/// Opens a job by its name.
///
/// The job name.
/// The desired access to the job object.
public JobObjectHandle(string name, JobObjectAccess access)
{
this.Handle = Win32.OpenJobObject(access, false, name);
if (this.Handle == IntPtr.Zero)
Win32.ThrowLastError();
}
///
/// Opens the job associated with the specified process.
///
/// The process.
/// The desired access to the job object.
public JobObjectHandle(ProcessHandle processHandle, JobObjectAccess access)
{
try
{
this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle, access));
}
catch (WindowsException)
{
// Use KPH to set the handle's granted access.
this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle,
(JobObjectAccess)StandardRights.Synchronize));
KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access);
}
if (this.Handle == IntPtr.Zero)
Win32.ThrowLastError();
}
private T QueryStruct(JobObjectInformationClass informationClass)
{
int retLength;
using (MemoryAlloc data = new MemoryAlloc(Marshal.SizeOf(typeof(T))))
{
if (!Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength))
{
data.Resize(retLength);
if (!Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength))
Win32.ThrowLastError();
}
return data.ReadStruct();
}
}
public JobObjectBasicAccountingInformation GetBasicAccountingInformation()
{
return this.QueryStruct(
JobObjectInformationClass.JobObjectBasicAccountingInformation);
}
public JobObjectBasicAndIoAccountingInformation GetBasicAndIoAccountingInformation()
{
return this.QueryStruct(
JobObjectInformationClass.JobObjectBasicAndIoAccountingInformation);
}
public JobObjectBasicLimitInformation GetBasicLimitInformation()
{
return this.QueryStruct(JobObjectInformationClass.JobObjectBasicLimitInformation);
}
public int[] GetProcessIdList()
{
List processIds = new List();
int retLength;
// FIXME: Fixed buffer
using (MemoryAlloc data = new MemoryAlloc(0x1000))
{
if (!Win32.QueryInformationJobObject(this, JobObjectInformationClass.JobObjectBasicProcessIdList,
data, data.Size, out retLength))
Win32.ThrowLastError();
JobObjectBasicProcessIdList listInfo = data.ReadStruct();
for (int i = 0; i < listInfo.NumberOfProcessIdsInList; i++)
{
processIds.Add(data.ReadInt32(8, i));
}
}
return processIds.ToArray();
}
public JobObjectBasicUiRestrictions GetBasicUiRestrictions()
{
JobObjectBasicUiRestrictions uiRestrictions;
int retLength;
if (!Win32.QueryInformationJobObject(this, JobObjectInformationClass.JobObjectBasicUIRestrictions,
out uiRestrictions, 4, out retLength))
Win32.ThrowLastError();
return uiRestrictions;
}
public JobObjectExtendedLimitInformation GetExtendedLimitInformation()
{
return this.QueryStruct(JobObjectInformationClass.JobObjectExtendedLimitInformation);
}
public void Terminate()
{
this.Terminate(0);
}
public void Terminate(int exitCode)
{
if (!Win32.TerminateJobObject(this, exitCode))
Win32.ThrowLastError();
}
}
[Flags]
public enum JobObjectInformationClass : int
{
JobObjectBasicAccountingInformation = 1,
JobObjectBasicLimitInformation,
JobObjectBasicProcessIdList,
JobObjectBasicUIRestrictions,
JobObjectSecurityLimitInformation,
JobObjectEndOfJobTimeInformation,
JobObjectAssociateCompletionPortInformation,
JobObjectBasicAndIoAccountingInformation,
JobObjectExtendedLimitInformation,
JobObjectJobSetInformation
}
[Flags]
public enum JobObjectLimitFlags : uint
{
WorkingSet = 0x1,
ProcessTime = 0x2,
JobTime = 0x4,
ActiveProcess = 0x8,
Affinity = 0x10,
PriorityClass = 0x20,
PreserveJobTime = 0x40,
SchedulingClass = 0x80,
ProcessMemory = 0x100,
JobMemory = 0x200,
DieOnUnhandledException = 0x400,
BreakawayOk = 0x800,
SilentBreakawayOk = 0x1000,
KillOnJobClose = 0x2000,
}
[Flags]
public enum JobObjectBasicUiRestrictions : uint
{
Handles = 0x1,
ReadClipboard = 0x2,
WriteClipboard = 0x4,
SystemParameters = 0x8,
DisplaySettings = 0x10,
GlobalAtoms = 0x20,
Desktop = 0x40,
ExitWindows = 0x80
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectBasicAccountingInformation
{
public long TotalUserTime;
public long TotalKernelTime;
public long ThisPeriodTotalUserTime;
public long ThisPeriodTotalKernelTime;
public int TotalPageFaultCount;
public int TotalProcesses;
public int ActiveProcesses;
public int TotalTerminatedProcesses;
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectBasicAndIoAccountingInformation
{
public JobObjectBasicAccountingInformation BasicInfo;
public IoCounters IoInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectBasicLimitInformation
{
public long PerProcessUserTimeLimit;
public long PerJobUserTimeLimit;
public JobObjectLimitFlags LimitFlags;
public int MinimumWorkingSetSize;
public int MaximumWorkingSetSize;
public int ActiveProcessLimit;
public int Affinity;
public int PriorityClass;
public int SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectBasicProcessIdList
{
public int NumberOfAssignedProcesses;
public int NumberOfProcessIdsInList;
/* an array follows */
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectEndOfJobTimeInformation
{
public int EndOfJobTimeAction; // 0: Terminate, 1: Post
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectExtendedLimitInformation
{
public JobObjectBasicLimitInformation BasicLimitInformation;
public IoCounters IoInfo;
public int ProcessMemoryLimit;
public int JobMemoryLimit;
public int PeakProcessMemoryUsed;
public int PeakJobMemoryUsed;
}
}