CreateJobObject / SetInformationJobObject在.net中的工作示例pinvoke?
我正在努力拼凑一个创造性的CreateJobObject和SetInformationJobObject工作示例。 通过各种谷歌search(包括俄罗斯和中国的post!)我拼凑了下面的代码。 我认为JOBOBJECT_BASIC_LIMIT_INFORMATION的定义基于平台(32/64位)进行更改。 CreateJobObject / AssignProcessToJobObject 似乎工作。 SetInformationJobObject失败 – 错误24或87。
Process myProcess // POPULATED SOMEWHERE ELSE // Create Job & assign this process and another process to the job IntPtr jobHandle = CreateJobObject( null , null ); AssignProcessToJobObject( jobHandle , myProcess.Handle ); AssignProcessToJobObject( jobHandle , Process.GetCurrentProcess().Handle ); // Ensure that killing one process kills the others JOBOBJECT_BASIC_LIMIT_INFORMATION limits = new JOBOBJECT_BASIC_LIMIT_INFORMATION(); limits.LimitFlags = (short)LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; IntPtr pointerToJobLimitInfo = Marshal.AllocHGlobal( Marshal.SizeOf( limits ) ); Marshal.StructureToPtr( limits , pointerToJobLimitInfo , false ); SetInformationJobObject( job , JOBOBJECTINFOCLASS.JobObjectBasicLimitInformation , pionterToJobLimitInfo , ( uint )Marshal.SizeOf( limits ) ) ... [DllImport( "kernel32.dll" , EntryPoint = "CreateJobObjectW" , CharSet = CharSet.Unicode )] public static extern IntPtr CreateJobObject( SecurityAttributes JobAttributes , string lpName ); public class SecurityAttributes { public int nLength; //Useless field = 0 public IntPtr pSecurityDescriptor; //хз)) public bool bInheritHandle; //Возможность наследования public SecurityAttributes() { this.bInheritHandle = true; this.nLength = 0; this.pSecurityDescriptor = IntPtr.Zero; } } [DllImport( "kernel32.dll" )] static extern bool SetInformationJobObject( IntPtr hJob , JOBOBJECTINFOCLASS JobObjectInfoClass , IntPtr lpJobObjectInfo , uint cbJobObjectInfoLength ); public enum JOBOBJECTINFOCLASS { JobObjectAssociateCompletionPortInformation = 7 , JobObjectBasicLimitInformation = 2 , JobObjectBasicUIRestrictions = 4 , JobObjectEndOfJobTimeInformation = 6 , JobObjectExtendedLimitInformation = 9 , JobObjectSecurityLimitInformation = 5 } [StructLayout( LayoutKind.Sequential )] struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public Int64 PerProcessUserTimeLimit; public Int64 PerJobUserTimeLimit; public Int16 LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public Int16 ActiveProcessLimit; public Int64 Affinity; public Int16 PriorityClass; public Int16 SchedulingClass; } public enum LimitFlags { JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008 , JOB_OBJECT_LIMIT_AFFINITY = 0x00000010 , JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800 , JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400 , JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200 , JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004 , JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000 , JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040 , JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020 , JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100 , JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002 , JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080 , JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000 , JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001 } [DllImport( "kernel32.dll" )] [return: MarshalAs( UnmanagedType.Bool )] static extern bool AssignProcessToJobObject( IntPtr hJob , IntPtr hProcess ); [StructLayout( LayoutKind.Sequential )] public struct SECURITY_ATTRIBUTES { public int nLength; public IntPtr lpSecurityDescriptor; public int bInheritHandle; }
这可能有点晚,但仍然。
我在这里尝试了所有的例子,但没有人同时在32位和64位模式下工作。 最后,我需要自己检查所有签名,并创build相应的PInvoke例程。 我想,其他人可以find这个帮助。
免责声明:该解决scheme是基于马特Howells的答案 。
using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace JobManagement { public class Job : IDisposable { [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] static extern IntPtr CreateJobObject(IntPtr a, string lpName); [DllImport("kernel32.dll")] static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); [DllImport("kernel32.dll", SetLastError = true)] static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseHandle(IntPtr hObject); private IntPtr handle; private bool disposed; public Job() { 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())); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (disposed) return; if (disposing) { } Close(); disposed = true; } public void Close() { CloseHandle(handle); handle = IntPtr.Zero; } public bool AddProcess(IntPtr processHandle) { return AssignProcessToJobObject(handle, processHandle); } public bool AddProcess(int processId) { return AddProcess(Process.GetProcessById(processId).Handle); } } #region Helper classes [StructLayout(LayoutKind.Sequential)] struct IO_COUNTERS { public UInt64 ReadOperationCount; public UInt64 WriteOperationCount; public UInt64 OtherOperationCount; public UInt64 ReadTransferCount; public UInt64 WriteTransferCount; public UInt64 OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public Int64 PerProcessUserTimeLimit; public Int64 PerJobUserTimeLimit; public UInt32 LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public UInt32 ActiveProcessLimit; public UIntPtr Affinity; public UInt32 PriorityClass; public UInt32 SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public UInt32 nLength; public IntPtr lpSecurityDescriptor; public Int32 bInheritHandle; } [StructLayout(LayoutKind.Sequential)] struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed; } public enum JobObjectInfoType { AssociateCompletionPortInformation = 7, BasicLimitInformation = 2, BasicUIRestrictions = 4, EndOfJobTimeInformation = 6, ExtendedLimitInformation = 9, SecurityLimitInformation = 5, GroupInformation = 11 } #endregion }
有一个post使用您正在尝试使用的apis。 也许你可以从那里得到一些见解。
当父进程被终止时,终止subprocess
总而言之,Alexander Yezutov在x86和x64下签名。 马特Howells签名使用UIntPtr时,应使用一些UInt32的。 我使用以下P / Invoke签名的CloseHandle似乎工作正常:
[DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr hObject);
必须将以下内容添加到Mas发布的app.manifest中:
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!-- A list of all Windows versions that this application is designed to work with. Windows will automatically select the most compatible environment.--> <!--The ID below indicates application support for Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!--The ID below indicates application support for Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> </application>
最后,从Visual Studio启动时,这将不起作用(至less在Win 7下)。 父进程必须从Windows资源pipe理器启动。
亚历山大的回答,这是一个使用SafeHandle
的版本。 这是一个CriticalFinalizerObject
,使处理更安全。 .NET API(例如Process
类)总是使用SafeHandle
来代替IntPtr
来使用P / Invoke。
internal sealed class ChildProcessManager : IDisposable { private SafeJobHandle _handle; private bool _disposed; 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 void Dispose() { if (_disposed) return; _handle.Dispose(); _handle = null; _disposed = true; } private void ValidateDisposed() { if (_disposed) throw new ObjectDisposedException(nameof(ChildProcessManager)); } public void AddProcess(SafeProcessHandle processHandle) { ValidateDisposed(); if (!AssignProcessToJobObject(_handle, processHandle)) { throw new InvalidOperationException("Unable to add the process"); } } public void AddProcess(Process process) { AddProcess(process.SafeHandle); } public void AddProcess(int processId) { using (var process = Process.GetProcessById(processId)) { AddProcess(process); } } #region Safe Handle // ReSharper disable once ClassNeverInstantiated.Local private sealed class SafeJobHandle : SafeHandleZeroOrMinusOneIsInvalid { public SafeJobHandle(IntPtr handle) : base(true) { SetHandle(handle); } protected override bool ReleaseHandle() { return CloseHandle(handle); } [DllImport("kernel32", SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private static extern bool CloseHandle(IntPtr hObject); } #endregion #region Win32 // ReSharper disable InconsistentNaming [DllImport("kernel32", CharSet = CharSet.Unicode)] private static extern IntPtr CreateJobObject(IntPtr a, string lpName); [DllImport("kernel32")] private static extern bool SetInformationJobObject(SafeJobHandle hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength); [DllImport("kernel32", SetLastError = true)] private static extern bool AssignProcessToJobObject(SafeJobHandle job, SafeProcessHandle process); [StructLayout(LayoutKind.Sequential)] internal struct IO_COUNTERS { public ulong ReadOperationCount; public ulong WriteOperationCount; public ulong OtherOperationCount; public ulong ReadTransferCount; public ulong WriteTransferCount; public ulong OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public long PerProcessUserTimeLimit; public long PerJobUserTimeLimit; public uint LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public uint ActiveProcessLimit; public UIntPtr Affinity; public uint PriorityClass; public uint SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public uint nLength; public IntPtr lpSecurityDescriptor; public int bInheritHandle; } [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed; } public enum JobObjectInfoType { AssociateCompletionPortInformation = 7, BasicLimitInformation = 2, BasicUIRestrictions = 4, EndOfJobTimeInformation = 6, ExtendedLimitInformation = 9, SecurityLimitInformation = 5, GroupInformation = 11 } // ReSharper restore InconsistentNaming #endregion }