■ Process 클래스를 사용해 부모 프로세스 종료시 자식 프로세스를 종료시키는 방법을 보여준다.
▶ JobObjectInfoType.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
namespace TestProject; /// <summary> /// 작업 객체 정보 타입 /// </summary> public enum JobObjectInformationType { /// <summary> /// Associate Completion Port Information /// </summary> AssociateCompletionPortInformation = 7, /// <summary> /// Basic Limit Information /// </summary> BasicLimitInformation = 2, /// <summary> /// Basic UI Restrictions /// </summary> BasicUIRestrictions = 4, /// <summary> /// End Of Job Time Information /// </summary> EndOfJobTimeInformation = 6, /// <summary> /// Extended Limit Information /// </summary> ExtendedLimitInformation = 9, /// <summary> /// Security Limit Information /// </summary> SecurityLimitInformation = 5, /// <summary> /// Group Information /// </summary> GroupInformation = 11 } |
▶ JobObjectLimit.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
namespace TestProject; /// <summary> /// 작업 객체 제한 /// </summary> [Flags] public enum JobObjectLimit : uint { /// <summary> /// Job Object Limit Kill On Job Close /// </summary> JobObjectLimitKillOnJobClose = 0x2000 } |
▶ IO_COUNTERS.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// IO 카운트 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct IO_COUNTERS { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 읽기 연산 카운트 /// </summary> public ulong ReadOperationCount; /// <summary> /// 쓰기 연산 카운트 /// </summary> public ulong WriteOperationCount; /// <summary> /// 기타 연산 카운트 /// </summary> public ulong OtherOperationCount; /// <summary> /// 읽기 전송 카운트 /// </summary> public ulong ReadTransferCount; /// <summary> /// 쓰기 전송 카운트 /// </summary> public ulong WriteTransferCount; /// <summary> /// 기타 전송 카운트 /// </summary> public ulong OtherTransferCount; #endregion } |
▶ JOB_OBJECT_BASIC_LIMIT_INFORMATION.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// 작업 객체 기본 제한 정보 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct JOB_OBJECT_BASIC_LIMIT_INFORMATION { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 프로세스당 사용자 시간 제한 /// </summary> public long PerProcessUserTimeLimit; /// <summary> /// 작업당 사용자 시간 제한 /// </summary> public long PerJobUserTimeLimit; /// <summary> /// 제한 플래그 /// </summary> public JobObjectLimit LimitFlags; /// <summary> /// 최소 작업 세트 크기 /// </summary> public UIntPtr MinimumWorkingSetSize; /// <summary> /// 최대 작업 세트 크기 /// </summary> public UIntPtr MaximumWorkingSetSize; /// <summary> /// 액티브 프로세스 제한 /// </summary> public uint ActiveProcessLimit; /// <summary> /// 친화도 /// </summary> public long Affinity; /// <summary> /// 우선 순위 클래스 /// </summary> public uint PriorityClass; /// <summary> /// 스케쥴링 클래스 /// </summary> public uint SchedulingClass; #endregion } |
▶ JOB_OBJECT_EXTENDED_LIMIT_INFORMATION.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// 작업 객체 확장 제한 정보 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct JOB_OBJECT_EXTENDED_LIMIT_INFORMATION { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 기본 제한 정보 /// </summary> public JOB_OBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; /// <summary> /// IO 정보 /// </summary> public IO_COUNTERS IOInformation; /// <summary> /// 프로세스 메모리 제한 /// </summary> public UIntPtr ProcessMemoryLimit; /// <summary> /// 작업 메모리 제한 /// </summary> public UIntPtr JobMemoryLimit; /// <summary> /// 피크 프로세스 사용 메모리 /// </summary> public UIntPtr PeakProcessMemoryUsed; /// <summary> /// 피크 작업 사용 메모리 /// </summary> public UIntPtr PeakJobMemoryUsed; #endregion } |
▶ SECURITY_ATTRIBUTES.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// 보안 특성 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// 길이 /// </summary> public int Length; /// <summary> /// 보안 설명자 /// </summary> public IntPtr SecurityDescriptor; /// <summary> /// 상속 핸들 /// </summary> public int InheritHandle; #endregion } |
▶ ChildProcessTracker.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; namespace TestProject; /// <summary> /// 자식 프로세스 추적자 /// </summary> public static class ChildProcessTracker { //////////////////////////////////////////////////////////////////////////////////////////////////// Import ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 작업 객체 생성하기 - CreateJobObject(jobAttributesHandle, name) /// <summary> /// 작업 객체 생성하기 /// </summary> /// <param name="jobAttributesHandle">작업 특성 핸들</param> /// <param name="name">명칭</param> /// <returns>작업 핸들</returns> [DllImport("kernel32", CharSet = CharSet.Unicode)] private static extern IntPtr CreateJobObject(IntPtr jobAttributesHandle, string name); #endregion #region 작업 객체 정보 설정하기 - SetInformationJobObject(jobHandle, jobObjectInformationType, jobObjectInformationHandle, jobObjectInformationLength) /// <summary> /// 작업 객체 정보 설정하기 /// </summary> /// <param name="jobHandle">작업 핸들</param> /// <param name="jobObjectInformationType">작업 객체 정보 타입</param> /// <param name="jobObjectInformationHandle">작업 객체 정보 핸들</param> /// <param name="jobObjectInformationLength">작업 객체 정보 길이</param> /// <returns>처리 결과</returns> [DllImport("kernel32")] private static extern bool SetInformationJobObject ( IntPtr jobHandle, JobObjectInformationType jobObjectInformationType, IntPtr jobObjectInformationHandle, uint jobObjectInformationLength ); #endregion #region 작업 객체에 프로세스 할당하기 - AssignProcessToJobObject(jobHandle, processHandle) /// <summary> /// 작업 객체에 프로세스 할당하기 /// </summary> /// <param name="jobHandle">작업 핸들</param> /// <param name="processHandle">프로세스 핸들</param> /// <returns>처리 결과</returns> [DllImport("kernel32", SetLastError = true)] private static extern bool AssignProcessToJobObject(IntPtr jobHandle, IntPtr processHandle); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Import ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 작업 핸들 /// </summary> private static readonly IntPtr _jobHandle; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Static #region 생성자 - ChildProcessTracker() /// <summary> /// 생성자 /// </summary> static ChildProcessTracker() { if(Environment.OSVersion.Version < new Version(6, 2)) { return; } string jobName = $"ChildProcessTracker{Process.GetCurrentProcess().Id}"; _jobHandle = CreateJobObject(IntPtr.Zero, jobName); JOB_OBJECT_BASIC_LIMIT_INFORMATION jobObjectBasicLimitInformation = new JOB_OBJECT_BASIC_LIMIT_INFORMATION(); jobObjectBasicLimitInformation.LimitFlags = JobObjectLimit.JobObjectLimitKillOnJobClose; JOB_OBJECT_EXTENDED_LIMIT_INFORMATION jobObjectExtendedLimitInformation = new JOB_OBJECT_EXTENDED_LIMIT_INFORMATION(); jobObjectExtendedLimitInformation.BasicLimitInformation = jobObjectBasicLimitInformation; int length = Marshal.SizeOf(typeof(JOB_OBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr jobObjectInformationHandle = Marshal.AllocHGlobal(length); try { Marshal.StructureToPtr(jobObjectExtendedLimitInformation, jobObjectInformationHandle, false); if(!SetInformationJobObject(_jobHandle, JobObjectInformationType.ExtendedLimitInformation, jobObjectInformationHandle, (uint)length)) { throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(jobObjectInformationHandle); } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 프로세스 추가하기 - AddProcess(process) /// <summary> /// 프로세스 추가하기 /// </summary> /// <param name="process">프로세스</param> public static void AddProcess(Process process) { if(_jobHandle != IntPtr.Zero) { bool success = AssignProcessToJobObject(_jobHandle, process.Handle); if(!success && !process.HasExited) { throw new Win32Exception(); } } } #endregion } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using System.Diagnostics; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { Process childProcess = Process.Start("notepad.exe"); ChildProcessTracker.AddProcess(childProcess); Console.WriteLine("프로그램을 종료하기 위해서 아무 키나 눌러 주시기 바랍니다."); Console.ReadKey(false); } #endregion } |