views:

1434

answers:

2

Question: How can I determine all processes in the child's Process Tree to kill them?

I have an application, written in C# that will:

  1. Get a set of data from the server,
  2. Spawn a 3rd party utility to process the data, then
  3. Return the results to the server.

This is working fine. But since a run consumes a lot of CPU and may take as long as an hour, I want to add the ability to have my app terminate its child processes.

Some issues that make the simple solutions I've found elsewhere are:

  • My app's child process "A" (InstallAnywhere EXE I think) spawns the real processing app "B" (a java.exe), which in turns spawns more children "C1".."Cn" (most of which are also written in Java).
  • There will likely be multiple copies of my application (and hence, multiple sets of its children) running on the same machine.
  • The child process is not in my control so there might be some "D" processes in the future.
  • My application must run on 32-bit and 64-bit versions of MSWindows.

On the plus side there is no issue of data loss, a "clean" shutdown doesn't matter as long as the processes end fairly quickly.

+1  A: 

I guess you can kill your grandchildren with this code from the MSDN forums.

public bool killProcess(int pid)
 {
  bool didIkillAnybody = false;
  try
  {
   Process[] procs = Process.GetProcesses();
   for (int i = 0; i < procs.Length; i++)
   {
    didIkillAnybody = GetParentProcess(procsIdea.Id) == pid) &&
                                   killProcess(procsIdea.Id);
   }
   try
   {
    Process myProc = Process.GetProcessById(pid);
    myProc.Kill();
    return true;
   }
   catch { }
  }
  catch (Exception ex)
  {
   try
   {
    new Logger().Write("Exception caught at JobExecution.killProcess()", ex.Message, System.Diagnostics.EventLogEntryType.Warning, false);
   }
   catch { }
  }
  return didIkillAnybody;
 }

 private int GetParentProcess(int Id)
 {
  int parentPid = 0;
  using (ManagementObject mo = new ManagementObject("win32_process.handle='" + Id.ToString() + "'"))
  {
   mo.Get();
   parentPid = Convert.ToInt32(mo["ParentProcessId"]);
  }
  return parentPid;
 }
Jake Pearson
In my case "B" could spawn another "C" if I didn't kill "B" first, so this wouldn't work, but it led me to the correct answer. I needed to get the list of process ID's and *then* kill them top-down. My solution builds a tree in one pass through Process.GetProcesses(), then the caller can kill them top-down or bottom-up, or can just use the data of the tree.
NVRAM
+1  A: 

I tested Jake Pearson's solution and for me this does not always work. I wanted to kill other process (with known pid) tree. The other process was using iexplore.exe running separately for each instance (IE 8 - more than one process). It works fine, but when used with WinAPI to hide IE window it stopped working.

I found solution on microsoft.public.dotnet.framework group, and it works fine now. Although Jake's answer can be useful in most cases, I think.

prostynick
That collects all children in a ArrayList, not as a tree (and it's unnecessarily recursive). Glad you found your solution - but I for one hate PInvokes and avoid them like the plague.
NVRAM
I don't like PInvokes either, but unfortunately I have something to do that requires me to use a lot of that :/ I hope this solution will be useful for somebody else searching for it :)
prostynick