代码之家  ›  专栏  ›  技术社区  ›  SiberianGuy

终止父进程时终止子进程

  •  137
  • SiberianGuy  · 技术社区  · 14 年前

    System.Diagnostics.Process 我申请的课程。



    有没有办法使子进程依赖于父进程?

    12 回复  |  直到 4 年前
        1
  •  0
  •   user1234567    3 年前

    this forum ,归功于“乔希”。

    Application.Quit() Process.Kill() 是可能的解决方案,但已被证明是不可靠的。当主应用程序停止运行时,您仍然可以运行子进程。我们真正想要的是主进程一死,子进程就死。

    解决方法是使用“作业对象” http://msdn.microsoft.com/en-us/library/ms682409(VS.85).aspx

    其思想是为主应用程序创建一个“job对象”,并用job对象注册子进程。如果主进程死亡,操作系统将负责终止子进程。

    public enum JobObjectInfoType
    {
        AssociateCompletionPortInformation = 7,
        BasicLimitInformation = 2,
        BasicUIRestrictions = 4,
        EndOfJobTimeInformation = 6,
        ExtendedLimitInformation = 9,
        SecurityLimitInformation = 5,
        GroupInformation = 11
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    struct JOBOBJECT_BASIC_LIMIT_INFORMATION
    {
        public Int64 PerProcessUserTimeLimit;
        public Int64 PerJobUserTimeLimit;
        public Int16 LimitFlags;
        public UInt32 MinimumWorkingSetSize;
        public UInt32 MaximumWorkingSetSize;
        public Int16 ActiveProcessLimit;
        public Int64 Affinity;
        public Int16 PriorityClass;
        public Int16 SchedulingClass;
    }
    
    [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_EXTENDED_LIMIT_INFORMATION
    {
        public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
        public IO_COUNTERS IoInfo;
        public UInt32 ProcessMemoryLimit;
        public UInt32 JobMemoryLimit;
        public UInt32 PeakProcessMemoryUsed;
        public UInt32 PeakJobMemoryUsed;
    }
    
    public class Job : IDisposable
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        static extern IntPtr CreateJobObject(object a, string lpName);
    
        [DllImport("kernel32.dll")]
        static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
    
        private IntPtr m_handle;
        private bool m_disposed = false;
    
        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()));
        }
    
        #region IDisposable Members
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        #endregion
    
        private void Dispose(bool disposing)
        {
            if (m_disposed)
                return;
    
            if (disposing) {}
    
            Close();
            m_disposed = true;
        }
    
        public void Close()
        {
            Win32.CloseHandle(m_handle);
            m_handle = IntPtr.Zero;
        }
    
        public bool AddProcess(IntPtr handle)
        {
            return AssignProcessToJobObject(m_handle, handle);
        }
    
    }
    

    看看构造器。。。

    JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
    info.LimitFlags = 0x2000;
    

    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE .

    导致所有与 作业的句柄已关闭。

    一旦这个类设置好了…你只需要注册每个子进程就可以了。例如:

    [DllImport("user32.dll", SetLastError = true)]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    
    Excel.Application app = new Excel.ApplicationClass();
    
    uint pid = 0;
    Win32.GetWindowThreadProcessId(new IntPtr(app.Hwnd), out pid);
     job.AddProcess(Process.GetProcessById((int)pid).Handle);