Basically the child process runs indefinitely until killed in the background, and I want to clean it up when my program terminates for any reason, i.e. via the Taskmanager.
Currently I have a while (Process.GetProcessesByName("ParentProcess").Count() > 0) loop and exit if the parent process isn't running, but it seems pretty brittle, and if I wanted it to work under debugger in Visual Studio I'd have to add "ParentProcess.vshost" or something.
Is there any way to make sure that the child process end without requiring the child process to know about the parent process? I'd prefer a solution in managed code, but if there isn't one I can PInvoke.
Edit: Passing the PID seems like a more robust solution, but for curiosity's sake, what if the child process was not my code but some exe that I have no control over? Is there a way to safeguard against possibly creating orphaned child processes?
If the child process is your own code, you could pass it the PID of the parent process when you launch it. The child process could then fetch the process with Process.GetProcessById
and subscribe to its Exited
event with a handler which shuts down the rest of the (child) process gracefully. Note that you need to set the EnableRaisingEvents
property on the process to true
.
If the child process is not your own code you can use this code to find and kill all child processes:
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;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With