Here is the source code for a small utility application that I built (it is based on a solution by Alan Hensel, which I found very useful).
It is called ChildrenProcessKiller, and it is an observer that allows you to kill all the processes of the descendants of this parent process when the parent process terminates (even if the parent process fails)
Using:
ChildrenProcessKiller.exe parentProcessId
Warning: this code is provided "as is" and it can kill small children ;-)
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; } } }
Pascal T.
source share