내 프로세스가 종료 될 때 내 프로그램에 의해 스폰 된 배경 프로세스가 사망 할 수있는 방법이 있습니까?

StackOverflow https://stackoverflow.com/questions/632148

  •  08-07-2019
  •  | 
  •  

문제

기본적으로 자식 프로세스는 백그라운드에서 죽일 때까지 무기한으로 실행되며, 어떤 이유로 든 TaskManager를 통해 프로그램이 종료되면 정리하고 싶습니다.

현재는 시간이 오래 걸리고 있습니다 (Process.GetProcessesByName ( "ParentProcess"). count ()> 0) 루프 및 출구가 실행되지 않으면 종료하지만 꽤 부서지기 쉬운 것처럼 보이지만 Visual에서 디버거 아래에서 작동하기를 원한다면 스튜디오 "ParentProcess.vshost"또는 무언가를 추가해야합니다.

아동 프로세스가 부모 과정에 대해 알 수 있도록 아동 프로세스가 끝나지 않도록하는 방법이 있습니까? 관리자 코드에서 솔루션을 선호하지만 코드가 없으면 Pinvoke를 할 수 있습니다.

편집 : PID를 통과하는 것은 더 강력한 솔루션처럼 보이지만 호기심을 위해서는 어린이 프로세스가 내 코드가 아니라 통제 할 수없는 일부 EXE라면 어떨까요? 고아 아동 프로세스를 만들 가능성을 방지 할 수있는 방법이 있습니까?

도움이 되었습니까?

해결책

자식 프로세스가 자신의 코드 인 경우, 출시시 부모 프로세스의 PID를 전달할 수 있습니다. 아동 과정은 프로세스를 가져올 수 있습니다 Process.GetProcessById 그리고 그것의 구독 Exited 나머지 (자식) 프로세스를 정상적으로 종료하는 핸들러가있는 이벤트. 설정해야합니다 EnableRaisingEvents 프로세스의 재산 true.

다른 팁

자식 프로세스가 자신의 코드가 아닌 경우이 코드를 사용하여 모든 아동 프로세스를 찾아 죽일 수 있습니다.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Util {
    public static class ProcessExtensions {
        public static void KillDescendants(this Process processToNotKillYet) {
            foreach (var eachProcess in Process.GetProcesses()) {
                if (eachProcess.ParentPid() == processToNotKillYet.Id) {
                    eachProcess.KillTree();
                }
            }
        }

        public static void KillTree(this Process processToKill) {
            processToKill.KillDescendants();
            processToKill.Kill();
        }

        public static PROCESS_BASIC_INFORMATION Info(this Process process) {
            var processInfo = new PROCESS_BASIC_INFORMATION();
            try {
                uint bytesWritten;
                NtQueryInformationProcess(process.Handle,
                                          0,
                                          ref processInfo,
                                          (uint)Marshal.SizeOf(processInfo),
                                          out bytesWritten); // == 0 is OK
            }
            catch (Win32Exception e) {
                if (!e.Message.Equals("Access is denied")) throw;
            }

            return processInfo;
        }

        public static int ParentPid(this Process process) {
            return process.Info().ParentPid;
        }

        [DllImport("ntdll.dll")]
        private static extern int NtQueryInformationProcess(
            IntPtr hProcess,
            int processInformationClass /* 0 */,
            ref PROCESS_BASIC_INFORMATION processBasicInformation,
            uint processInformationLength,
            out uint returnLength);

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_BASIC_INFORMATION {
            public int ExitStatus;
            public int PebBaseAddress;
            public int AffinityMask;
            public int BasePriority;
            public int Pid;
            public int ParentPid;
        }
    }
}

그러한 아동 프로세스에 대한 일반적인 용어는 고아 과정. 가능한 솔루션은 링크 된 기사를 참조하십시오.

여기에 제작 한 작은 유틸리티 앱의 소스 코드 (Alan Hensel 솔루션을 기반으로합니다. 매우 유용한 것으로 나타났습니다).

이를 childrenprocesskiller라고하며 부모 프로세스가 종료 될 때 (부모 프로세스가 충돌하더라도) 주어진 부모 프로세스의 모든 후손 프로세스를 죽일 수있는 감시자입니다.

용법 :

ChildrenProcessKiller.exe parentProcessId

경고 :이 코드는 "있는 그대로"제공되며 작은 아기를 죽일 수 있습니다 ;-)

childrenprocesskiller.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ChildrenProcessKiller
{
  static class ChildrenProcessKiller
  {
    [STAThread]
    static void Main(string[] args)
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);

      string message = "This is a watcher that enables to kill all descendants process of a given parent process\n";
      message += "when the parent process exits (even if the parent process crashes) \n\n";
      message += "Usage : " + Application.ExecutablePath + " parentProcessId";

      if (args.Length != 1)
      {
        MessageBox.Show(message);
        System.Environment.Exit(1);
      }

      int parentProcessId;
      if (!Int32.TryParse(args[0], out parentProcessId))
      {
        MessageBox.Show(message);
        System.Environment.Exit(1);
      }

      try
      {
        mParentProcess = Process.GetProcessById(parentProcessId);
      }
      catch (System.ArgumentException ex)
      {
        //Parent process cannot be found!
        System.Environment.Exit(2);
      }
      Run();
    }

    private static List<Process> mChildrenProcesses;
    private static Process mParentProcess;

    private static void Run()
    {
      int thisProcessId = Process.GetCurrentProcess().Id;
      while ( ! mParentProcess.HasExited )
      {
        RefreshChildrenProcesses();
        System.Threading.Thread.Sleep(1000);
      }

      foreach (Process childProcess in mChildrenProcesses)
      {
        if ((!childProcess.HasExited) && (childProcess.Id != thisProcessId))
        {
          KillGracefullyThenViolently(childProcess);
        }
      }
    }

    private static void KillGracefullyThenViolently(Process process)
    {
      if (process.HasExited)
        return;

      try
      {
        process.CloseMainWindow();
      }
      catch (PlatformNotSupportedException)
      {}
      catch (InvalidOperationException)
      {}//do nothing : this app is meant to be "unstoppable", unless the parent process has exited

      for (int i = 0; i < 15; i++)
      {
        System.Threading.Thread.Sleep(100);
        if (process.HasExited)
          return;
      }

      try
      {
        process.Kill();
      }
      catch (System.ComponentModel.Win32Exception)
      {}
      catch(NotSupportedException)
      {}
      catch(InvalidOperationException)
      {} //same comment here
    }

    private static void RefreshChildrenProcesses()
    {
      if (mParentProcess.HasExited)
        return;
      List<Process> newChildren;
      try
      {
        newChildren = Utils.ProcessTree.GetProcessDescendants(mParentProcess);
        mChildrenProcesses = newChildren;
      }
      catch (System.Exception ex)
      {
        ; 
      }
    }


  }
}

ProcessTree.cs

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace Utils
{
  public static class ProcessTree
  {

    public static List<Process> GetProcessDescendants(Process process)
    {
      List<Process> result = new List<Process>();
      foreach (Process eachProcess in Process.GetProcesses())
      {
        if (ParentPid(eachProcess) == process.Id)
        {
          result.Add(eachProcess);
        }
      }
      return result;
    }

    public static void KillDescendants(Process processToNotKillYet) 
    {
      foreach (Process eachProcess in Process.GetProcesses()) 
      {
        if (ParentPid(eachProcess) == processToNotKillYet.Id) 
        {
          if (eachProcess.Id != Process.GetCurrentProcess().Id)
            KillTree(eachProcess);
        }
      }
    }

    public static void KillTree(Process processToKill) 
    {
      KillDescendants(processToKill);
      processToKill.Kill();
    }

    public static PROCESS_BASIC_INFORMATION Info(Process process) 
    {
      PROCESS_BASIC_INFORMATION processInfo = new PROCESS_BASIC_INFORMATION();
      try
      {
        uint bytesWritten;
        NtQueryInformationProcess(process.Handle,
                        0,
                        ref processInfo,
                        (uint)Marshal.SizeOf(processInfo),
                        out bytesWritten); // == 0 is OK
      }
      catch (Win32Exception e) 
      {
        if (!e.Message.Equals("Access is denied")) throw;
      }

      return processInfo;
    }

    public static int ParentPid(Process process) 
    {
      return Info(process).ParentPid;
    }

    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(
      IntPtr hProcess,
      int processInformationClass /* 0 */,
      ref PROCESS_BASIC_INFORMATION processBasicInformation,
      uint processInformationLength,
      out uint returnLength);

    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_BASIC_INFORMATION 
    {
      public int ExitStatus;
      public int PebBaseAddress;
      public int AffinityMask;
      public int BasePriority;
      public int Pid;
      public int ParentPid;
    }
  }
}

부모 프로세스 ID를 명령 줄 매개 변수로 전달하여 하위 프로세스로 전달하십시오.

아동 프로세스에서 ID에 의한 프로세스 받기 및 출구 이벤트를 구독하거나 스레드를 생성하고 프로세스를 호출합니다. waitforexit

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top