| 
									
										
										
										
											2023-01-01 11:42:01 +00:00
										 |  |  |  | using System.Diagnostics; | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  | using System.Runtime.InteropServices; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-19 10:15:54 +00:00
										 |  |  |  | namespace ServiceLib.Common | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |     /* | 
					
						
							|  |  |  |  |      * See: | 
					
						
							|  |  |  |  |      * http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net | 
					
						
							|  |  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-14 02:57:40 +00:00
										 |  |  |  |     public sealed class Job : IDisposable | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |         private IntPtr handle = IntPtr.Zero; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         public Job() | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             handle = CreateJobObject(IntPtr.Zero, null); | 
					
						
							| 
									
										
										
										
											2020-03-14 19:25:40 +00:00
										 |  |  |  |             IntPtr extendedInfoPtr = IntPtr.Zero; | 
					
						
							| 
									
										
										
										
											2023-02-19 05:34:22 +00:00
										 |  |  |  |             JOBOBJECT_BASIC_LIMIT_INFORMATION info = new() | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |             { | 
					
						
							|  |  |  |  |                 LimitFlags = 0x2000 | 
					
						
							|  |  |  |  |             }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-19 05:34:22 +00:00
										 |  |  |  |             JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new() | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |             { | 
					
						
							|  |  |  |  |                 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, | 
					
						
							| 
									
										
										
										
											2023-01-01 11:42:01 +00:00
										 |  |  |  |                         (uint)length)) | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |                     throw new Exception(string.Format("Unable to set information.  Error: {0}", | 
					
						
							|  |  |  |  |                         Marshal.GetLastWin32Error())); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             finally | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 if (extendedInfoPtr != IntPtr.Zero) | 
					
						
							|  |  |  |  |                 { | 
					
						
							|  |  |  |  |                     Marshal.FreeHGlobal(extendedInfoPtr); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         public bool AddProcess(IntPtr processHandle) | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-03-14 19:25:40 +00:00
										 |  |  |  |             bool succ = AssignProcessToJobObject(handle, processHandle); | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (!succ) | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2024-01-10 02:43:48 +00:00
										 |  |  |  |                 Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             return succ; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         public bool AddProcess(int processId) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return AddProcess(Process.GetProcessById(processId).Handle); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         #region IDisposable | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         private bool disposed; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         public void Dispose() | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             Dispose(true); | 
					
						
							|  |  |  |  |             GC.SuppressFinalize(this); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-14 02:57:40 +00:00
										 |  |  |  |         private void Dispose(bool disposing) | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |             if (disposed) return; | 
					
						
							|  |  |  |  |             disposed = true; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (disposing) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 // no managed objects to free | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (handle != IntPtr.Zero) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 CloseHandle(handle); | 
					
						
							|  |  |  |  |                 handle = IntPtr.Zero; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         ~Job() | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             Dispose(false); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  |         #endregion IDisposable | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         #region Interop | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] | 
					
						
							| 
									
										
										
										
											2023-02-19 05:34:22 +00:00
										 |  |  |  |         private static extern IntPtr CreateJobObject(IntPtr a, string? lpName); | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         [DllImport("kernel32.dll", SetLastError = true)] | 
					
						
							|  |  |  |  |         private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         [DllImport("kernel32.dll", SetLastError = true)] | 
					
						
							|  |  |  |  |         private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         [DllImport("kernel32.dll", SetLastError = true)] | 
					
						
							|  |  |  |  |         [return: MarshalAs(UnmanagedType.Bool)] | 
					
						
							|  |  |  |  |         private static extern bool CloseHandle(IntPtr hObject); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  |         #endregion Interop | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     #region Helper classes | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [StructLayout(LayoutKind.Sequential)] | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  |     internal struct IO_COUNTERS | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |         public UInt64 ReadOperationCount; | 
					
						
							|  |  |  |  |         public UInt64 WriteOperationCount; | 
					
						
							|  |  |  |  |         public UInt64 OtherOperationCount; | 
					
						
							|  |  |  |  |         public UInt64 ReadTransferCount; | 
					
						
							|  |  |  |  |         public UInt64 WriteTransferCount; | 
					
						
							|  |  |  |  |         public UInt64 OtherTransferCount; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     [StructLayout(LayoutKind.Sequential)] | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  |     internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |         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)] | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  |     internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION | 
					
						
							| 
									
										
										
										
											2019-10-11 06:15:20 +00:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |         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 | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 12:49:36 +00:00
										 |  |  |  |     #endregion Helper classes | 
					
						
							|  |  |  |  | } |