diff --git a/Netch/Controllers/HTTPController.cs b/Netch/Controllers/HTTPController.cs index 1ff5fdfd..421c05ae 100644 --- a/Netch/Controllers/HTTPController.cs +++ b/Netch/Controllers/HTTPController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Threading.Tasks; using System.Windows.Forms; @@ -33,7 +33,7 @@ namespace Netch.Controllers { if (pPrivoxyController.Start(MainController.ServerController.Server, mode)) { - ChildProcessTracker.AddProcess(pPrivoxyController.Instance); + Global.Job.AddProcess(pPrivoxyController.Instance); } if (mode.Type == 3) NativeMethods.SetGlobal($"127.0.0.1:{Global.Settings.HTTPLocalPort}", IEProxyExceptions); diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index 0338c7ae..34b1fe58 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net; using System.Threading.Tasks; @@ -128,7 +128,7 @@ namespace Netch.Controllers { if (guard.Instance != null) { - ChildProcessTracker.AddProcess(guard.Instance); + Global.Job.AddProcess(guard.Instance); } } @@ -170,7 +170,7 @@ namespace Netch.Controllers { if (guard.Instance != null) { - ChildProcessTracker.AddProcess(guard.Instance); + Global.Job.AddProcess(guard.Instance); } } diff --git a/Netch/Global.cs b/Netch/Global.cs index 1877dc16..7187b669 100644 --- a/Netch/Global.cs +++ b/Netch/Global.cs @@ -1,14 +1,14 @@ -using System; +using Netch.Controllers; +using Netch.Forms; +using Netch.Models; +using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -using System.Threading.Tasks; using System.Windows.Forms; -using Netch.Controllers; -using Netch.Forms; -using Netch.Models; +using WindowsJobAPI; namespace Netch { @@ -87,5 +87,10 @@ namespace Netch /// 用于存储模式 /// public static readonly List Modes = new List(); + + /// + /// Windows Job API + /// + public static readonly JobObject Job = new JobObject(); } } \ No newline at end of file diff --git a/Netch/Netch.csproj b/Netch/Netch.csproj index d958fbf0..9891bf9f 100644 --- a/Netch/Netch.csproj +++ b/Netch/Netch.csproj @@ -72,6 +72,7 @@ + diff --git a/Netch/Utils/ChildProcessTracker.cs b/Netch/Utils/ChildProcessTracker.cs deleted file mode 100644 index 750954cd..00000000 --- a/Netch/Utils/ChildProcessTracker.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Netch.Utils -{ - /// - /// Allows processes to be automatically killed if this parent process unexpectedly quits. - /// This feature requires Windows 8 or greater. On Windows 7, nothing is done. - /// References: - /// https://stackoverflow.com/a/4657392/386091 - /// https://stackoverflow.com/a/9164742/386091 - public static class ChildProcessTracker - { - /// - /// Add the process to be tracked. If our current process is killed, the child processes - /// that we are tracking will be automatically killed, too. If the child process terminates - /// first, that's fine, too. - /// - public static void AddProcess(Process process) - { - if (s_jobHandle != IntPtr.Zero) - { - var success = AssignProcessToJobObject(s_jobHandle, process.Handle); - if (!success && !process.HasExited) - throw 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 - var 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. - info.LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - - var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION - { - BasicLimitInformation = info - }; - - var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); - var 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); - } - } - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string name); - - [DllImport("kernel32.dll")] - private static extern bool SetInformationJobObject(IntPtr job, JobObjectInfoType infoType, - IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); - - // Windows will automatically close any open job handles when our process terminates. - // This can be verified by using SysInternals' Handle utility. When the job handle - // is closed, the child processes will be killed. - private static readonly IntPtr s_jobHandle; - } - - public enum JobObjectInfoType - { - AssociateCompletionPortInformation = 7, - BasicLimitInformation = 2, - BasicUIRestrictions = 4, - EndOfJobTimeInformation = 6, - ExtendedLimitInformation = 9, - SecurityLimitInformation = 5, - GroupInformation = 11 - } - - [StructLayout(LayoutKind.Sequential)] - public struct JOBOBJECT_BASIC_LIMIT_INFORMATION - { - public Int64 PerProcessUserTimeLimit; - public Int64 PerJobUserTimeLimit; - public JOBOBJECTLIMIT LimitFlags; - public UIntPtr MinimumWorkingSetSize; - public UIntPtr MaximumWorkingSetSize; - public UInt32 ActiveProcessLimit; - public Int64 Affinity; - public UInt32 PriorityClass; - public UInt32 SchedulingClass; - } - - [Flags] - public enum JOBOBJECTLIMIT : uint - { - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000 - } - - [StructLayout(LayoutKind.Sequential)] - public struct IO_COUNTERS - { - public UInt64 ReadOperationCount; - public UInt64 WriteOperationCount; - public UInt64 OtherOperationCount; - public UInt64 ReadTransferCount; - public UInt64 WriteTransferCount; - public UInt64 OtherTransferCount; - } - - [StructLayout(LayoutKind.Sequential)] - public 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; - } -} \ No newline at end of file