Task: Auto kill all child processes if parent process terminate. Parent procees can be terminated not only in correct way, but also by killing in ProcessExplorer, for example. How can I do it?
Similar question in С topic advice to use Job objects. How to use it in C# without exporting external DLL?
I tried to use Job Objects. But this code doesn't work properly:
var job = PInvoke.CreateJobObject(null, null);
var jobli = new PInvoke.JOBOBJECT_BASIC_LIMIT_INFORMATION();
jobli.LimitFlags = PInvoke.LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_PRIORITY_CLASS
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_TIME
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_MEMORY;
var res = PInvoke.SetInformationJobObject(job, PInvoke.JOBOBJECTINFOCLASS.JobObjectBasicLimitInformation, jobli, 48);
if (!res)
{
int b = PInvoke.GetLastError();
Console.WriteLine("Error " + b);
}
var Prc = Process.Start(...);
PInvoke.AssignProcessToJobObject(job, Prc.Handle);
PInvoke.SetInformationJobObject returns with error. GetLastError returns error 24. However, PInvoke.AssignProcessToJobObject works and child process added to Job Queue (I can see it in ProcessExplorer). But, because PInvoke.SetInformationJobObject don't work - spawned process stay alive when I kill parent one.
What do I have incorrect in this code?
To kill a process tree on windows, given only the parent process or process id, you'll need to walk the process tree.
For that, you'll need a way to get the parent process id for a given process.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Management;
namespace KillProcessTree
{
public static class MyExtensions
{
public static int GetParentProcessId(this Process p)
{
int parentId = 0;
try
{
ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
mo.Get();
parentId = Convert.ToInt32(mo["ParentProcessId"]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
parentId = 0;
}
return parentId;
}
}
Once you have that, actually killing the tree is not hard.
class Program
{
/// <summary>
/// Kill specified process and all child processes
/// </summary>
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: KillProcessTree <pid>");
return;
}
int pid = int.Parse(args[0]);
Process root = Process.GetProcessById(pid);
if (root != null)
{
Console.WriteLine("KillProcessTree " + pid);
var list = new List<Process>();
GetProcessAndChildren(Process.GetProcesses(), root, list, 1);
// kill each process
foreach (Process p in list)
{
try
{
p.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
else
{
Console.WriteLine("Unknown process id: " + root);
}
}
/// <summary>
/// Get process and children
/// We use postorder (bottom up) traversal; good as any when you kill a process tree </summary>
/// </summary>
/// <param name="plist">Array of all processes</param>
/// <param name="parent">Parent process</param>
/// <param name="output">Output list</param>
/// <param name="indent">Indent level</param>
private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
{
foreach (Process p in plist)
{
if (p.GetParentProcessId() == parent.Id)
{
GetProcessAndChildren(plist, p, output, indent + 1);
}
}
output.Add(parent);
Console.WriteLine(String.Format("{0," + indent*4 + "} {1}", parent.Id, parent.MainModule.ModuleName));
}
}
} // namespace