Gibt es eine Möglichkeit, dass ein Hintergrundprozess durch mein Programm wird getötet, als mein Prozess beendet hervorgebracht zu machen?

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

  •  08-07-2019
  •  | 
  •  

Frage

Im Grunde genommen das Kind Prozess läuft auf unbestimmte Zeit, bis im Hintergrund getötet, und ich möchte es bereinigen, wenn mein Programm aus irgendeinem Grunde beendet, das heißt über den Taskmanager.

Zur Zeit habe ich eine Weile (Process.GetProcessesByName ( „ParentProcess“). Count ()> 0) Schleife und Ausgang, wenn der übergeordnete Prozess nicht ausgeführt wird, aber es scheint ziemlich spröde, und wenn ich es wollte unter arbeiten Debugger in Visual Studio muss ich würde "ParentProcess.vshost" oder etwas hinzuzufügen.

Gibt es eine Möglichkeit, um sicherzustellen, dass das Kind Prozess, ohne dass das Kind Prozess beenden zu dem übergeordneten Prozess wissen? Ich würde eine Lösung in verwaltetem Code bevorzugen, aber wenn es nicht ein, ich kann PInvoke.

Edit: scheint die PID Passing wie eine robustere Lösung, aber für Neugier willen, was ist, wenn das Kind Prozess nicht mein Code war aber einige exe, dass ich keine Kontrolle darüber? Gibt es eine Möglichkeit zum Schutz gegen möglicherweise verwaistes Kind schöpfenden Prozesse?

War es hilfreich?

Lösung

Wenn das Kind Prozess Ihr eigener Code ist, können Sie es die PID des übergeordneten Prozesses passieren, wenn Sie es starten. Das Kind Prozess könnte dann den Prozess holen mit Process.GetProcessById und abonnieren Sie seine Exited Veranstaltung anmutig mit einem Handler, der den Rest des (Kind) Prozess heruntergefahren. Beachten Sie, dass Sie die EnableRaisingEvents festlegen müssen Immobilien auf den Prozess true.

Andere Tipps

Wenn das Kind Prozess nicht Ihren eigenen Code, den Sie diesen Code alle untergeordneten Prozesse verwenden können, zu finden und zu töten:

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;
        }
    }
}

Die allgemeine Bezeichnung für ein solches Kind-Prozess in wie Waise Prozess . Siehe den verlinkten Artikel für einige mögliche Lösungen.

Hier ist ein Quellcode für ein kleines Programm App I gebaut (Es ist auf Basis von Alan Hensel Lösung, die ich sehr nützlich gefunden).

Es heißt ChildrenProcessKiller und es ist ein Beobachter, der alle Nachkommen Prozess eines bestimmten übergeordneten Prozess töten können, wenn die übergeordnete Prozess beendet wird (auch wenn der übergeordnete Prozess stürzt ab)

Verbrauch:

ChildrenProcessKiller.exe parentProcessId

Achtung: Dieser Code wird „wie sie ist“, und es könnte kleine Babys töten ;-)

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;
    }
  }
}

Führen Sie den übergeordneten Prozess-ID als Befehlszeilenparameter untergeordneten Prozess.

Kindprozess Verwendung Prozess von id bekommen und abonnieren Sie es Exit-Ereignis ist oder einen Thread erstellen und rufen zu Process.WaitForExit

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top