public ProcessContainer(Process p, Job j) { _proc = p; _job = j; handle = CreateJobObject(IntPtr.Zero, null); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x2000 }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } // Set the value to an unknown Result = InteractionResult.Unknown; }
public Job() { const uint JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000; const uint JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x800; _handle = CreateJobObject(IntPtr.Zero, null); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } }
/// <summary> /// Initializes a new instance of the <see cref="AttachedChildProcessJob"/> class. /// </summary> /// <param name="process">The process.</param> public AttachedChildProcessJob(Process process) { jobHandle = CreateJobObject(IntPtr.Zero, null); var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOBOBJECTLIMIT.KillOnJobClose } }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { return; } AssignProcessToJobObject(jobHandle, process.Handle); }
public ChildProcessManager(ulong memoryLimit) { _handle = new SafeJobHandle(CreateJobObject(IntPtr.Zero, null)); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x00000100 }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info, ProcessMemoryLimit = (UIntPtr)memoryLimit }; var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new InvalidOperationException($"Unable to set information. Error: {Marshal.GetLastWin32Error()}"); } }
private static SafeFileHandle CreateJobHandle() { var handle = NativeMethods.CreateJobObject(IntPtr.Zero, null); if (handle == null) { throw new LastWin32ErrorException("Error creating job handle"); } var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION(); info.LimitFlags = 0x2000; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); extendedInfo.BasicLimitInformation = info; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!NativeMethods.SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new LastWin32ErrorException("Unable to set job information"); } return(handle); } finally { Marshal.FreeHGlobal(extendedInfoPtr); } }
/// <summary> /// Constructor /// </summary> public ManagedProcessGroup() { if (SupportsJobObjects) { // Create the job object that the child process will be added to JobHandle = CreateJobObject(IntPtr.Zero, IntPtr.Zero); if (JobHandle == null) { throw new Win32Exception(); } // Configure the job object to terminate the processes added to it when the handle is closed JOBOBJECT_EXTENDED_LIMIT_INFORMATION LimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); LimitInformation.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK; int Length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr LimitInformationPtr = Marshal.AllocHGlobal(Length); Marshal.StructureToPtr(LimitInformation, LimitInformationPtr, false); if (SetInformationJobObject(JobHandle, JobObjectExtendedLimitInformation, LimitInformationPtr, Length) == 0) { throw new Win32Exception(); } } }
public Job() { handle = CreateJobObject(IntPtr.Zero, null); if (handle.IsInvalid) { throw new Win32Exception(); } var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE } }; int cbJobObjectInfo = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr lpJobObjectInfo = Marshal.AllocHGlobal(cbJobObjectInfo); try { Marshal.StructureToPtr(extendedInfo, lpJobObjectInfo, false); if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, ref extendedInfo, cbJobObjectInfo)) { throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(lpJobObjectInfo); } }
public static IntPtr CreateKillOnCloseJob() { IntPtr job = CreateJobObject(IntPtr.Zero, null); if (job == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var info = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); int returnLength = 0; if (!QueryInformationJobObject(job, JOBOBJECTINFOCLASS.ExtendedLimitInformation, ref info, Marshal.SizeOf(info), ref returnLength)) { var error = Marshal.GetLastWin32Error(); CloseHandle(job); throw new Win32Exception(error); } info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK; if (!SetInformationJobObject(job, JOBOBJECTINFOCLASS.ExtendedLimitInformation, ref info, (uint)Marshal.SizeOf(info))) { var error = Marshal.GetLastWin32Error(); CloseHandle(job); throw new Win32Exception(error); } return(job); }
public unsafe WindowsProcessKillJob() { jobHandle = Kernel32.CreateJobObject(IntPtr.Zero, IntPtr.Zero); if (jobHandle == IntPtr.Zero) { throw new Win32Exception(); } try { var limitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOBOBJECT_BASIC_LIMIT_FLAGS.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE } }; var cb = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION); if (!Kernel32.SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, ref limitInformation, (uint)cb)) { throw new Win32Exception(); } } catch (Exception) { Kernel32.CloseHandle(jobHandle); throw; } }
public static IntPtr Create() { /* * Windows will automatically close any open job handles when our process terminates. * This can be verified by using SysInternals' readHandle utility. When the job handle * is closed, the child processes will be killed. * * This feature requires Windows 8 or later. To support Windows 7 requires * registry settings to be added if you are using Visual Studio plus an * app.manifest change. */ if (!Environment.OSVersion.IsWindows8OrHigher()) { return(IntPtr.Zero); } // The job name is optional (and can be null) but it helps with diagnostics. // If it's not null, it has to be unique. Use SysInternals' Handle command-line // utility: handle -a ChildProcessTracker string jobName = "ChildProcessTracker" + Process.GetCurrentProcess().Id; IntPtr jobHandle = Win32.CreateJobObject(IntPtr.Zero, jobName); JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JobObjectLimitEnum.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE }; // This is the key flag. When our process is killed, Windows will automatically // close the job handle, and when that happens, we want the child processes to // be killed, too. JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!Win32.SetInformationJobObject(jobHandle, JobObjectInfoTypeEnum.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { Marshal.FreeHGlobal(extendedInfoPtr); } return(jobHandle); }
static void AttachChildProcessToThisProcess(Process proc) { //Attach 'proc' process to this process, so that it's closed along with this process try { if (ghJob == IntPtr.Zero) { ghJob = CreateJobObject(IntPtr.Zero, ""); //It will be closed automatically when this process exits or is terminated if (ghJob == IntPtr.Zero) { throw new Win32Exception(); } } JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION(); info.LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; JOBOBJECT_EXTENDED_LIMIT_INFORMATION exInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); exInfo.BasicLimitInformation = info; int nLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr exInfoPtr = Marshal.AllocHGlobal(nLength); try { Marshal.StructureToPtr(exInfo, exInfoPtr, false); if (!SetInformationJobObject(ghJob, JobObjectInfoType.ExtendedLimitInformation, exInfoPtr, (uint)nLength)) { throw new Win32Exception(); } //And attach the process if (!AssignProcessToJobObject(ghJob, proc.Handle)) { throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(exInfoPtr); } } catch (Exception ex) { //Error gEventLog.logMessage(EventLogMsgType.ELM_TYP_Error, "Failed to assign miner job: " + ex.ToString()); OutputConsoleError("ERROR: Failed to assign miner job: " + ex.ToString()); } }
/// <summary> /// Sets limits. /// </summary> /// <param name="activeProcessLimit">The number of processes that can be added to the job object.</param> /// <param name="jobMemoryLimitInBytes">The total amount of memory that can be consumed by all processes in the job object.</param> /// <param name="limitFlags">The limits that are in effect.</param> /// <param name="processMemoryLimitInBytes">The maximum number of bytes a process can consume.</param> public void SetLimits( uint? activeProcessLimit = null, ulong? jobMemoryLimitInBytes = null, JOB_OBJECT_LIMIT_FLAGS limitFlags = JOB_OBJECT_LIMIT_FLAGS.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, ulong? processMemoryLimitInBytes = null) { this.tracer.Trace(nameof(JobObject), "Setting limits"); var extendedLimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = { LimitFlags = limitFlags, }, }; if (activeProcessLimit.HasValue) { extendedLimitInformation.BasicLimitInformation.ActiveProcessLimit = activeProcessLimit.GetValueOrDefault(); extendedLimitInformation.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_FLAGS.JOB_OBJECT_LIMIT_ACTIVE_PROCESS; } if (jobMemoryLimitInBytes.HasValue) { extendedLimitInformation.JobMemoryLimit = new UIntPtr(jobMemoryLimitInBytes.GetValueOrDefault()); extendedLimitInformation.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_FLAGS.JOB_OBJECT_LIMIT_JOB_MEMORY; } if (processMemoryLimitInBytes.HasValue) { extendedLimitInformation.ProcessMemoryLimit = new UIntPtr(processMemoryLimitInBytes.GetValueOrDefault()); extendedLimitInformation.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_FLAGS.JOB_OBJECT_LIMIT_PROCESS_MEMORY; } // Apply the limits to the job object. using (var nativeExtendedLimitInformation = new SafeHGlobalBuffer(Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)))) { Marshal.StructureToPtr(extendedLimitInformation, nativeExtendedLimitInformation.DangerousGetHandle(), fDeleteOld: false); if (!Methods.SetInformationJobObject( this.handle, JOB_OBJECT_INFO_CLASS.JobObjectExtendedLimitInformation, nativeExtendedLimitInformation.DangerousGetHandle(), nativeExtendedLimitInformation.Size)) { throw new SandboxException( "Unable to set job object limit information", new Win32Exception()); } } }
static ChildProcessTracker() { // This feature requires Windows 8 or later. To support Windows 7 requires // registry settings to be added if you are using Visual Studio plus an // app.manifest change. // https://stackoverflow.com/a/4232259/386091 // https://stackoverflow.com/a/9507862/386091 if (Environment.OSVersion.Version < new Version(6, 2)) { return; } // The job name is optional (and can be null) but it helps with diagnostics. // If it's not null, it has to be unique. Use SysInternals' Handle command-line // utility: handle -a ChildProcessTracker string jobName = "ChildProcessTracker" + Process.GetCurrentProcess().Id; s_jobHandle = CreateJobObject(IntPtr.Zero, jobName); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { // This is the key flag. When our process is killed, Windows will automatically // close the job handle, and when that happens, we want the child processes to // be killed, too. LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(s_jobHandle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(extendedInfoPtr); } }
static ProcessHelper() { job = CreateJobObject(IntPtr.Zero, null); JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION(); info.LimitFlags = 0x2000; JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); extendedInfo.BasicLimitInformation = info; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); SetInformationJobObject(job, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length); }
/// <summary> /// Initializes a new instance of the <see cref="ProcessJobTracker"/> class. /// </summary> public ProcessJobTracker() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return; } // The job name is optional (and can be null) but it helps with diagnostics. // If it's not null, it has to be unique. Use SysInternals' Handle command-line // utility: handle -a ChildProcessTracker string jobName = nameof(ProcessJobTracker) + Process.GetCurrentProcess().Id; this.jobHandle = CreateJobObject(IntPtr.Zero, jobName); var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOB_OBJECT_LIMIT_FLAGS.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, }, }; // This code can be a lot simpler if we use pointers, but since this class is so generally interesting // and may be copied and pasted to other projects that prefer to avoid unsafe code, we use Marshal and IntPtr's instead. int length = Marshal.SizeOf(extendedInfo); IntPtr pExtendedInfo = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(extendedInfo, pExtendedInfo, fDeleteOld: false); try { if (!SetInformationJobObject(this.jobHandle, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, pExtendedInfo, (uint)length)) { throw new Win32Exception(); } } finally { Marshal.DestroyStructure <JOBOBJECT_EXTENDED_LIMIT_INFORMATION>(pExtendedInfo); } } finally { Marshal.FreeHGlobal(pExtendedInfo); } }
public static void Start(Process process = null) { // this is here to make it so if the player crashes // the process it started is killed along with it if (!Started) { if (jobHandle == IntPtr.Zero) { jobHandle = CreateJobObject(IntPtr.Zero, null); if (jobHandle == IntPtr.Zero) { throw new JobObjectException("Could not create the Job Object."); } } JOBOBJECT_BASIC_LIMIT_INFORMATION jobobjectBasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOB_OBJECT_LIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE }; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobobjectExtendedLimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = jobobjectBasicLimitInformation }; int jobobjectExtendedLimitInformationSize = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr jobobjectExtendedLimitInformationPointer = Marshal.AllocHGlobal(jobobjectExtendedLimitInformationSize); Marshal.StructureToPtr(jobobjectExtendedLimitInformation, jobobjectExtendedLimitInformationPointer, false); bool result = SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, jobobjectExtendedLimitInformationPointer, (uint)jobobjectExtendedLimitInformationSize); Marshal.FreeHGlobal(jobobjectExtendedLimitInformationPointer); if (process == null) { process = Process.GetCurrentProcess(); } if (!result || !AssignProcessToJobObject(jobHandle, process.Handle)) { throw new JobObjectException("Could not set the Job Object Information or assign the Process to the Job Object."); } Started = true; } }
public void Init() { try { if (!m_IsInit) { m_JobHandle = CreateJobObject(IntPtr.Zero, null); if (m_JobHandle == IntPtr.Zero) { throw new Exception("Failed to create job handle"); } var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION() { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION() { LimitFlags = 0x2000 } }; var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(m_JobHandle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } m_Logger.Log($"Job initiated: {m_JobHandle}", LoggerMessageSeverity_e.Debug); m_IsInit = true; } else { throw new Exception("Job is already initialized"); } } catch (Exception ex) { m_Logger.Log(ex); throw; } }
public Job() { m_handle = CreateJobObject(null, null); JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION(); info.LimitFlags = 0x2000; JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); extendedInfo.BasicLimitInformation = info; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(m_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } }
public static JobObject CreateAsKillOnJobClose() { var job = new JobObject(); var jobInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION() { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION() { LimitFlags = JobObjectLimit.KillOnJobClose }, }; var size = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); if (!Native.SetInformationJobObject(job.SafeHandle, JobObjectInfoClass.ExtendedLimitInformation, ref jobInfo, size)) { throw new Win32Exception(); } return(job); }
public Job() { jobObjecthandler = CreateJobObject(IntPtr.Zero, "mongod"); var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x2000 } }; int extendedInfoObjLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(extendedInfoObjLength); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(jobObjecthandler, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)extendedInfoObjLength)) { throw new InvalidOperationException($"Unable to set information. win32 error: {Marshal.GetLastWin32Error()}"); } }
/// <summary> /// Initializes a new instance of the <see cref="AttachedChildProcessJob"/> class. /// </summary> /// <param name="process">The process.</param> public AttachedChildProcessJob(Process process) { jobHandle = CreateJobObject(IntPtr.Zero, null); var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOBOBJECTLIMIT.KillOnJobClose } }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) return; AssignProcessToJobObject(jobHandle, process.Handle); }
private static IntPtr IntiailizeProcessTracker() { // Requires Win8 or later if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || Environment.OSVersion.Version < new Version(6, 2)) { return(IntPtr.Zero); } // Job name is optional but helps with diagnostics. Job name must be unique if non-null. var jobHandle = CreateJobObject(IntPtr.Zero, name: $"ProcessTracker{Environment.ProcessId}"); var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE } }; var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(jobHandle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(extendedInfoPtr); } return(jobHandle); }
private static void SetProcessGroupLimits(IntPtr hGroupObject, uint limitFlags) { IntPtr hLimitInfo = IntPtr.Zero; JOBOBJECT_EXTENDED_LIMIT_INFORMATION limitInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); try { //HACK: For some reason, the SetInformationJobObject API returns a failure if you use BASIC_LIMIT structure //instead of the EXTENDED limit structure, even if we only care about the BASIC one. int returnLength = 0; int limitInfoSize = Marshal.SizeOf(limitInfo); hLimitInfo = Marshal.AllocHGlobal(limitInfoSize); //Retrieve the current limit info if (!QueryInformationJobObject(hGroupObject, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, hLimitInfo, limitInfoSize, ref returnLength)) { throw new Win32Exception(); } //Marshall the data between managed and unmanaged memory Marshal.PtrToStructure(hLimitInfo, limitInfo); limitInfo.BasicLimitInformation.LimitFlags |= limitFlags; Marshal.StructureToPtr(limitInfo, hLimitInfo, false); if (!SetInformationJobObject(hGroupObject, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, hLimitInfo, limitInfoSize)) { throw new Win32Exception(); } } finally { if (hLimitInfo != IntPtr.Zero) { Marshal.FreeHGlobal(hLimitInfo); } } }
/// <summary> /// Creates a new <see cref="ChildProcessManager"/>. /// </summary> public ChildProcessManager() { if (Common.IsPosixEnvironment) { // On non-Windows operating systems we just track associated processes m_childProcesses = new List <WeakReference <Process> >(); } else { // Let safe handle manage terminations on Windows GC.SuppressFinalize(this); // On Windows we add child processes to a job object such that when the job // is terminated, so are the child processes. Since safe handle ensures proper // closing of job handle, child processes will be terminated even if parent // process is abnormally terminated m_jobHandle = new SafeJobHandle(CreateJobObject(IntPtr.Zero, null)); JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x2000 }; JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(m_jobHandle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new InvalidOperationException($"Unable to set information for ChildProcessManager job. Error: {Marshal.GetLastWin32Error()}"); } } }
public WindowsProcessKillJob(ILog log) { this.log = log.ForContext <WindowsProcessKillJob>(); jobHandle = Kernel32.CreateJobObject(IntPtr.Zero, IntPtr.Zero); if (jobHandle == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } try { var limitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOBOBJECT_BASIC_LIMIT_FLAGS.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE } }; var cb = Marshal.SizeOf((object)limitInformation); jobObjectInfoPtr = Marshal.AllocHGlobal(cb); try { Marshal.StructureToPtr((object)limitInformation, jobObjectInfoPtr, false); if (!Kernel32.SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, jobObjectInfoPtr, (uint)cb)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } catch (Exception) { Marshal.FreeHGlobal(jobObjectInfoPtr); throw; } } catch (Exception) { Kernel32.CloseHandle(jobHandle); throw; } }
public JobObject() { handle = NativeMethods.CreateJobObject(IntPtr.Zero, null); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = KillOnJobClose }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!NativeMethods.SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } }
public ProcessJobTracker() { string jobName = nameof(ProcessJobTracker) + Process.GetCurrentProcess().Id; _jobHandle = Kernel32Wrapper.CreateJobObject(IntPtr.Zero, jobName); var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, }, }; int length = Marshal.SizeOf(extendedInfo); IntPtr pExtendedInfo = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(extendedInfo, pExtendedInfo, false); try { if (!Kernel32Wrapper.SetInformationJobObject(_jobHandle, JobObjectInfoType.ExtendedLimitInformation, pExtendedInfo, (uint)length)) { throw new Win32Exception(); } } finally { Marshal.DestroyStructure <JOBOBJECT_EXTENDED_LIMIT_INFORMATION>(pExtendedInfo); } } finally { Marshal.FreeHGlobal(pExtendedInfo); } }
public Job() { handle = CreateJobObject(IntPtr.Zero, null); var extendedInfoPtr = IntPtr.Zero; var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x2000 }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; try { int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } } finally { if (extendedInfoPtr != IntPtr.Zero) { Marshal.FreeHGlobal(extendedInfoPtr); extendedInfoPtr = IntPtr.Zero; } } }
public JobObject() { handle = NativeMethods.CreateJobObject(IntPtr.Zero, null); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = KillOnJobClose }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!NativeMethods.SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); } }
public ChildProcessManager() { _handle = new SafeJobHandle(CreateJobObject(IntPtr.Zero, null)); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x2000 }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new InvalidOperationException($"Unable to set information. Error: {Marshal.GetLastWin32Error()}"); } }
public static void Main(String[] args) { uint maxmem = 0; List <String> procargs = null; bool showhelp = false; int pid = 0; var p = new OptionSet() { { "m|maxmem=", "Max committed memory usage in bytes (accepted suffixes: K, M or G).", v => { if (v == null) { return; } if (v.EndsWith("K", StringComparison.OrdinalIgnoreCase)) { maxmem = UInt32.Parse(v.Substring(0, v.Length - 1)) << 10; return; } if (v.EndsWith("M", StringComparison.OrdinalIgnoreCase)) { maxmem = UInt32.Parse(v.Substring(0, v.Length - 1)) << 20; return; } if (v.EndsWith("G", StringComparison.OrdinalIgnoreCase)) { maxmem = UInt32.Parse(v.Substring(0, v.Length - 1)) << 30; return; } maxmem = UInt32.Parse(v); } }, { "p|pid=", "Attach to an already running process", (int v) => pid = v }, { "h|help", "Show this message and exit", v => showhelp = v != null }, { "?", "Show this message and exit", v => showhelp = v != null } }; try { procargs = p.Parse(args); } catch (OptionException ex) { Console.Write("ERROR: invalid argument "); Console.WriteLine(ex.Message); Console.WriteLine(); showhelp = true; } catch (FormatException) { Console.WriteLine("ERROR: invalid memory constraint"); Console.WriteLine(); showhelp = true; } if (!showhelp && (procargs.Count == 0 && pid == 0) || (pid > 0 && procargs.Count > 0)) { Console.WriteLine("ERROR: please provide either process name to start or PID of the already running process"); Console.WriteLine(); showhelp = true; } if (showhelp) { ShowHelp(p); return; } IntPtr hJob, hIOCP, hProcess; hJob = hIOCP = hProcess = IntPtr.Zero; PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); Thread listener = null; try { if (pid > 0) { // open existing process hProcess = CheckResult(ApiMethods.OpenProcess(ProcessAccessFlags.AllAccess, false, pid)); } else { // start suspended process pi = StartSuspendedProcess(procargs); hProcess = pi.hProcess; } var securityAttributes = new SECURITY_ATTRIBUTES(); securityAttributes.nLength = Marshal.SizeOf(securityAttributes); hJob = CheckResult(ApiMethods.CreateJobObject(ref securityAttributes, "procgov-" + Guid.NewGuid())); // create completion port hIOCP = CheckResult(ApiMethods.CreateIoCompletionPort(ApiMethods.INVALID_HANDLE_VALUE, IntPtr.Zero, IntPtr.Zero, 1)); var assocInfo = new JOBOBJECT_ASSOCIATE_COMPLETION_PORT { CompletionKey = IntPtr.Zero, CompletionPort = hIOCP }; uint size = (uint)Marshal.SizeOf(assocInfo); CheckResult(ApiMethods.SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.AssociateCompletionPortInformation, ref assocInfo, size)); // start listening thread listener = new Thread(CompletionPortListener); listener.Start(hIOCP); if (maxmem > 0.0f) { // configure constraints var limitInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = JobInformationLimitFlags.JOB_OBJECT_LIMIT_PROCESS_MEMORY | JobInformationLimitFlags.JOB_OBJECT_LIMIT_BREAKAWAY_OK | JobInformationLimitFlags.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK }, ProcessMemoryLimit = (UIntPtr)maxmem }; size = (uint)Marshal.SizeOf(limitInfo); CheckResult(ApiMethods.SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.ExtendedLimitInformation, ref limitInfo, size)); } // assign a process to a job to apply constraints CheckResult(ApiMethods.AssignProcessToJobObject(hJob, hProcess)); // resume process main thread (if it was started by us) if (pid == 0) { CheckResult(ApiMethods.ResumeThread(pi.hThread)); // and we can close the thread handle CloseHandle(pi.hThread); } if (ApiMethods.WaitForSingleObject(hProcess, ApiMethods.INFINITE) == 0xFFFFFFFF) { throw new Win32Exception(); } } finally { CloseHandle(hIOCP); // wait for the listener thread to finish if (listener != null && listener.IsAlive) { listener.Join(); } CloseHandle(hProcess); CloseHandle(hJob); } }
/// <summary> /// Spawns a new managed process. /// </summary> /// <param name="FileName">Path to the executable to be run</param> /// <param name="CommandLine">Command line arguments for the process</param> /// <param name="WorkingDirectory">Working directory for the new process. May be null to use the current working directory.</param> /// <param name="Environment">Environment variables for the new process. May be null, in which case the current process' environment is inherited</param> /// <param name="Input">Text to be passed via stdin to the new process. May be null.</param> public ManagedProcess(string FileName, string CommandLine, string WorkingDirectory, IReadOnlyDictionary <string, string> Environment, string Input, ManagedProcessPriority Priority, ulong MemoryLimit) { // Create the job object that the child process will be added to JobHandle = CreateJobObject(IntPtr.Zero, IntPtr.Zero); if (JobHandle == null) { throw new Win32Exception(); } // Configure the job object to terminate the processes added to it when the handle is closed JOBOBJECT_EXTENDED_LIMIT_INFORMATION LimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); LimitInformation.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_PROCESS_MEMORY; LimitInformation.ProcessMemoryLimit = new UIntPtr(MemoryLimit); int Length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr LimitInformationPtr = Marshal.AllocHGlobal(Length); Marshal.StructureToPtr(LimitInformation, LimitInformationPtr, false); if (SetInformationJobObject(JobHandle, JobObjectExtendedLimitInformation, LimitInformationPtr, Length) == 0) { throw new Win32Exception(); } // Create the child process IntPtr EnvironmentBlock = IntPtr.Zero; SafeFileHandle StdInRead = null; SafeFileHandle StdOutWrite = null; SafeWaitHandle StdErrWrite = null; try { // Create stdin and stdout pipes for the child process. We'll close the handles for the child process' ends after it's been created. SECURITY_ATTRIBUTES SecurityAttributes = new SECURITY_ATTRIBUTES(); SecurityAttributes.bInheritHandle = 1; if (CreatePipe(out StdInRead, out StdInWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdInWrite, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if (CreatePipe(out StdOutRead, out StdOutWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdOutRead, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if (DuplicateHandle(GetCurrentProcess(), StdOutWrite, GetCurrentProcess(), out StdErrWrite, DUPLICATE_SAME_ACCESS, true, 0) == 0) { throw new Win32Exception(); } // Create the environment block for the child process, if necessary. if (Environment != null) { // The native format for the environment block is a sequence of null terminated strings with a final null terminator. List <byte> EnvironmentBytes = new List <byte>(); foreach (KeyValuePair <string, string> Pair in Environment) { EnvironmentBytes.AddRange(Encoding.UTF8.GetBytes(Pair.Key)); EnvironmentBytes.Add((byte)'='); EnvironmentBytes.AddRange(Encoding.UTF8.GetBytes(Pair.Value)); EnvironmentBytes.Add((byte)0); } EnvironmentBytes.Add((byte)0); // Allocate an unmanaged block of memory to store it. EnvironmentBlock = Marshal.AllocHGlobal(EnvironmentBytes.Count); Marshal.Copy(EnvironmentBytes.ToArray(), 0, EnvironmentBlock, EnvironmentBytes.Count); } // Set the startup parameters for the new process STARTUPINFO StartupInfo = new STARTUPINFO(); StartupInfo.cb = Marshal.SizeOf(StartupInfo); StartupInfo.hStdInput = StdInRead; StartupInfo.hStdOutput = StdOutWrite; StartupInfo.hStdError = StdErrWrite; StartupInfo.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION ProcessInfo = new PROCESS_INFORMATION(); try { // Get the flags to create the new process ProcessCreationFlags Flags = ProcessCreationFlags.CREATE_NO_WINDOW | ProcessCreationFlags.CREATE_SUSPENDED | ProcessCreationFlags.CREATE_BREAKAWAY_FROM_JOB; switch (Priority) { case ManagedProcessPriority.BelowNormal: Flags |= ProcessCreationFlags.BELOW_NORMAL_PRIORITY_CLASS; break; case ManagedProcessPriority.Normal: Flags |= ProcessCreationFlags.NORMAL_PRIORITY_CLASS; break; case ManagedProcessPriority.AboveNormal: Flags |= ProcessCreationFlags.ABOVE_NORMAL_PRIORITY_CLASS; break; } // Create the new process as suspended, so we can modify it before it starts executing (and potentially preempting us) if (CreateProcess(null, new StringBuilder("\"" + FileName + "\" " + CommandLine), IntPtr.Zero, IntPtr.Zero, true, Flags, EnvironmentBlock, WorkingDirectory, StartupInfo, ProcessInfo) == 0) { throw new Win32Exception(); } // Add it to our job object if (AssignProcessToJobObject(JobHandle, ProcessInfo.hProcess) == 0) { throw new Win32Exception(); } // Allow the thread to start running if (ResumeThread(ProcessInfo.hThread) == -1) { throw new Win32Exception(); } // If we have any input text, write it to stdin now using (StreamWriter StdInWriter = new StreamWriter(new FileStream(StdInWrite, FileAccess.Write, 4096, false), Console.InputEncoding, 4096)) { if (!String.IsNullOrEmpty(Input)) { StdInWriter.WriteLine(Input); StdInWriter.Flush(); } } // Create the stream objects for reading the process output InnerStream = new FileStream(StdOutRead, FileAccess.Read, 4096, false); ReadStream = new StreamReader(InnerStream, Console.OutputEncoding); // Wrap the process handle in a SafeFileHandle ProcessHandle = new SafeFileHandle(ProcessInfo.hProcess, true); } finally { if (ProcessInfo.hProcess != IntPtr.Zero && ProcessHandle == null) { CloseHandle(ProcessInfo.hProcess); } if (ProcessInfo.hThread != IntPtr.Zero) { CloseHandle(ProcessInfo.hThread); } } } finally { if (EnvironmentBlock != IntPtr.Zero) { Marshal.FreeHGlobal(EnvironmentBlock); EnvironmentBlock = IntPtr.Zero; } if (StdInRead != null) { StdInRead.Dispose(); StdInRead = null; } if (StdOutWrite != null) { StdOutWrite.Dispose(); StdOutWrite = null; } if (StdErrWrite != null) { StdErrWrite.Dispose(); StdErrWrite = null; } } }
public static extern bool SetInformationJobObject(SafeJobHandle hJob, JobObjectInfoType infoType, ref JOBOBJECT_EXTENDED_LIMIT_INFORMATION lpJobObjectInfo, int cbJobObjectInfoLength);
public ChildProcess(string FileName, string CommandLine, string Input) { JobHandle = CreateJobObject(IntPtr.Zero, IntPtr.Zero); if(JobHandle == null) { throw new Win32Exception(); } JOBOBJECT_EXTENDED_LIMIT_INFORMATION LimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); LimitInformation.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; int Length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr LimitInformationPtr = Marshal.AllocHGlobal(Length); Marshal.StructureToPtr(LimitInformation, LimitInformationPtr, false); if(SetInformationJobObject(JobHandle, JobObjectExtendedLimitInformation, LimitInformationPtr, Length) == 0) { throw new Win32Exception(); } SafeFileHandle StdInRead = null; SafeFileHandle StdOutWrite = null; SafeWaitHandle StdErrWrite = null; try { SECURITY_ATTRIBUTES SecurityAttributes = new SECURITY_ATTRIBUTES(); SecurityAttributes.bInheritHandle = 1; if(CreatePipe(out StdInRead, out StdInWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdInWrite, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if(CreatePipe(out StdOutRead, out StdOutWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdOutRead, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if(DuplicateHandle(GetCurrentProcess(), StdOutWrite, GetCurrentProcess(), out StdErrWrite, DUPLICATE_SAME_ACCESS, true, 0) == 0) { throw new Win32Exception(); } STARTUPINFO StartupInfo = new STARTUPINFO(); StartupInfo.cb = Marshal.SizeOf(StartupInfo); StartupInfo.hStdInput = StdInRead; StartupInfo.hStdOutput = StdOutWrite; StartupInfo.hStdError = StdErrWrite; StartupInfo.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION ProcessInfo = new PROCESS_INFORMATION(); try { if(CreateProcess(null, new StringBuilder("\"" + FileName + "\" " + CommandLine), IntPtr.Zero, IntPtr.Zero, true, CREATE_NO_WINDOW | CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, new IntPtr(0), null, StartupInfo, ProcessInfo) == 0) { throw new Win32Exception(); } if(AssignProcessToJobObject(JobHandle, ProcessInfo.hProcess) == 0) { throw new Win32Exception(); } if(ResumeThread(ProcessInfo.hThread) == -1) { throw new Win32Exception(); } using(StreamWriter StdInWriter = new StreamWriter(new FileStream(StdInWrite, FileAccess.Write, 4096, false), Console.InputEncoding, 4096)) { if(!String.IsNullOrEmpty(Input)) { StdInWriter.WriteLine(Input); StdInWriter.Flush(); } } InnerStream = new FileStream(StdOutRead, FileAccess.Read, 4096, false); ReadStream = new StreamReader(InnerStream, Console.OutputEncoding); ProcessHandle = new SafeFileHandle(ProcessInfo.hProcess, true); } finally { if(ProcessInfo.hProcess != null && ProcessHandle == null) { CloseHandle(ProcessInfo.hProcess); } if(ProcessInfo.hThread != null) { CloseHandle(ProcessInfo.hThread); } } } finally { if(StdInRead != null) { StdInRead.Dispose(); StdInRead = null; } if(StdOutWrite != null) { StdOutWrite.Dispose(); StdOutWrite = null; } if(StdErrWrite != null) { StdErrWrite.Dispose(); StdErrWrite = null; } } }
public ChildProcess(string FileName, string CommandLine, string Input) { JobHandle = CreateJobObject(IntPtr.Zero, IntPtr.Zero); if (JobHandle == null) { throw new Win32Exception(); } JOBOBJECT_EXTENDED_LIMIT_INFORMATION LimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); LimitInformation.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; int Length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr LimitInformationPtr = Marshal.AllocHGlobal(Length); Marshal.StructureToPtr(LimitInformation, LimitInformationPtr, false); if (SetInformationJobObject(JobHandle, JobObjectExtendedLimitInformation, LimitInformationPtr, Length) == 0) { throw new Win32Exception(); } SafeFileHandle StdInRead = null; SafeFileHandle StdOutWrite = null; SafeWaitHandle StdErrWrite = null; try { SECURITY_ATTRIBUTES SecurityAttributes = new SECURITY_ATTRIBUTES(); SecurityAttributes.bInheritHandle = 1; if (CreatePipe(out StdInRead, out StdInWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdInWrite, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if (CreatePipe(out StdOutRead, out StdOutWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdOutRead, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if (DuplicateHandle(GetCurrentProcess(), StdOutWrite, GetCurrentProcess(), out StdErrWrite, DUPLICATE_SAME_ACCESS, true, 0) == 0) { throw new Win32Exception(); } STARTUPINFO StartupInfo = new STARTUPINFO(); StartupInfo.cb = Marshal.SizeOf(StartupInfo); StartupInfo.hStdInput = StdInRead; StartupInfo.hStdOutput = StdOutWrite; StartupInfo.hStdError = StdErrWrite; StartupInfo.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION ProcessInfo = new PROCESS_INFORMATION(); try { if (CreateProcess(null, new StringBuilder("\"" + FileName + "\" " + CommandLine), IntPtr.Zero, IntPtr.Zero, true, CREATE_NO_WINDOW | CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, new IntPtr(0), null, StartupInfo, ProcessInfo) == 0) { throw new Win32Exception(); } if (AssignProcessToJobObject(JobHandle, ProcessInfo.hProcess) == 0) { throw new Win32Exception(); } if (ResumeThread(ProcessInfo.hThread) == -1) { throw new Win32Exception(); } using (StreamWriter StdInWriter = new StreamWriter(new FileStream(StdInWrite, FileAccess.Write, 4096, false), Console.InputEncoding, 4096)) { if (!String.IsNullOrEmpty(Input)) { StdInWriter.WriteLine(Input); StdInWriter.Flush(); } } InnerStream = new FileStream(StdOutRead, FileAccess.Read, 4096, false); ReadStream = new StreamReader(InnerStream, Console.OutputEncoding); ProcessHandle = new SafeFileHandle(ProcessInfo.hProcess, true); } finally { if (ProcessInfo.hProcess != null && ProcessHandle == null) { CloseHandle(ProcessInfo.hProcess); } if (ProcessInfo.hThread != null) { CloseHandle(ProcessInfo.hThread); } } } finally { if (StdInRead != null) { StdInRead.Dispose(); StdInRead = null; } if (StdOutWrite != null) { StdOutWrite.Dispose(); StdOutWrite = null; } if (StdErrWrite != null) { StdErrWrite.Dispose(); StdErrWrite = null; } } }
public static extern bool SetInformationJobObject(IntPtr hJob, int infoType , ref JOBOBJECT_EXTENDED_LIMIT_INFORMATION lpJobObjectInfo, int cbJobObjectInfoLength);
/// <summary> /// Spawns a new managed process. /// </summary> /// <param name="FileName">Path to the executable to be run</param> /// <param name="CommandLine">Command line arguments for the process</param> /// <param name="WorkingDirectory">Working directory for the new process. May be null to use the current working directory.</param> /// <param name="Environment">Environment variables for the new process. May be null, in which case the current process' environment is inherited</param> /// <param name="Input">Text to be passed via stdin to the new process. May be null.</param> public ManagedProcess(string FileName, string CommandLine, string WorkingDirectory, IReadOnlyDictionary<string, string> Environment, string Input, ManagedProcessPriority Priority) { // Create the job object that the child process will be added to JobHandle = CreateJobObject(IntPtr.Zero, IntPtr.Zero); if(JobHandle == null) { throw new Win32Exception(); } // Configure the job object to terminate the processes added to it when the handle is closed JOBOBJECT_EXTENDED_LIMIT_INFORMATION LimitInformation = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); LimitInformation.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; int Length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr LimitInformationPtr = Marshal.AllocHGlobal(Length); Marshal.StructureToPtr(LimitInformation, LimitInformationPtr, false); if(SetInformationJobObject(JobHandle, JobObjectExtendedLimitInformation, LimitInformationPtr, Length) == 0) { throw new Win32Exception(); } // Create the child process IntPtr EnvironmentBlock = IntPtr.Zero; SafeFileHandle StdInRead = null; SafeFileHandle StdOutWrite = null; SafeWaitHandle StdErrWrite = null; try { // Create stdin and stdout pipes for the child process. We'll close the handles for the child process' ends after it's been created. SECURITY_ATTRIBUTES SecurityAttributes = new SECURITY_ATTRIBUTES(); SecurityAttributes.bInheritHandle = 1; if(CreatePipe(out StdInRead, out StdInWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdInWrite, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if(CreatePipe(out StdOutRead, out StdOutWrite, SecurityAttributes, 0) == 0 || SetHandleInformation(StdOutRead, HANDLE_FLAG_INHERIT, 0) == 0) { throw new Win32Exception(); } if(DuplicateHandle(GetCurrentProcess(), StdOutWrite, GetCurrentProcess(), out StdErrWrite, DUPLICATE_SAME_ACCESS, true, 0) == 0) { throw new Win32Exception(); } // Create the environment block for the child process, if necessary. if(Environment != null) { // The native format for the environment block is a sequence of null terminated strings with a final null terminator. List<byte> EnvironmentBytes = new List<byte>(); foreach(KeyValuePair<string, string> Pair in Environment) { EnvironmentBytes.AddRange(Encoding.UTF8.GetBytes(Pair.Key)); EnvironmentBytes.Add((byte)'='); EnvironmentBytes.AddRange(Encoding.UTF8.GetBytes(Pair.Value)); EnvironmentBytes.Add((byte)0); } EnvironmentBytes.Add((byte)0); // Allocate an unmanaged block of memory to store it. EnvironmentBlock = Marshal.AllocHGlobal(EnvironmentBytes.Count); Marshal.Copy(EnvironmentBytes.ToArray(), 0, EnvironmentBlock, EnvironmentBytes.Count); } // Set the startup parameters for the new process STARTUPINFO StartupInfo = new STARTUPINFO(); StartupInfo.cb = Marshal.SizeOf(StartupInfo); StartupInfo.hStdInput = StdInRead; StartupInfo.hStdOutput = StdOutWrite; StartupInfo.hStdError = StdErrWrite; StartupInfo.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION ProcessInfo = new PROCESS_INFORMATION(); try { // Get the flags to create the new process ProcessCreationFlags Flags = ProcessCreationFlags.CREATE_NO_WINDOW | ProcessCreationFlags.CREATE_SUSPENDED | ProcessCreationFlags.CREATE_BREAKAWAY_FROM_JOB; switch(Priority) { case ManagedProcessPriority.BelowNormal: Flags |= ProcessCreationFlags.BELOW_NORMAL_PRIORITY_CLASS; break; case ManagedProcessPriority.Normal: Flags |= ProcessCreationFlags.NORMAL_PRIORITY_CLASS; break; case ManagedProcessPriority.AboveNormal: Flags |= ProcessCreationFlags.ABOVE_NORMAL_PRIORITY_CLASS; break; } // Create the new process as suspended, so we can modify it before it starts executing (and potentially preempting us) if(CreateProcess(null, new StringBuilder("\"" + FileName + "\" " + CommandLine), IntPtr.Zero, IntPtr.Zero, true, Flags, EnvironmentBlock, WorkingDirectory, StartupInfo, ProcessInfo) == 0) { throw new Win32Exception(); } // Add it to our job object if(AssignProcessToJobObject(JobHandle, ProcessInfo.hProcess) == 0) { throw new Win32Exception(); } // Allow the thread to start running if(ResumeThread(ProcessInfo.hThread) == -1) { throw new Win32Exception(); } // If we have any input text, write it to stdin now using(StreamWriter StdInWriter = new StreamWriter(new FileStream(StdInWrite, FileAccess.Write, 4096, false), Console.InputEncoding, 4096)) { if(!String.IsNullOrEmpty(Input)) { StdInWriter.WriteLine(Input); StdInWriter.Flush(); } } // Create the stream objects for reading the process output InnerStream = new FileStream(StdOutRead, FileAccess.Read, 4096, false); ReadStream = new StreamReader(InnerStream, Console.OutputEncoding); // Wrap the process handle in a SafeFileHandle ProcessHandle = new SafeFileHandle(ProcessInfo.hProcess, true); } finally { if(ProcessInfo.hProcess != IntPtr.Zero && ProcessHandle == null) { CloseHandle(ProcessInfo.hProcess); } if(ProcessInfo.hThread != IntPtr.Zero) { CloseHandle(ProcessInfo.hThread); } } } finally { if(EnvironmentBlock != IntPtr.Zero) { Marshal.FreeHGlobal(EnvironmentBlock); EnvironmentBlock = IntPtr.Zero; } if(StdInRead != null) { StdInRead.Dispose(); StdInRead = null; } if(StdOutWrite != null) { StdOutWrite.Dispose(); StdOutWrite = null; } if(StdErrWrite != null) { StdErrWrite.Dispose(); StdErrWrite = null; } } }