Matar el árbol de procesos programáticamente en C #

Estoy iniciando Internet Explorer programáticamente con un código que se ve así:

ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe"); startInfo.WindowStyle = ProcessWindowStyle.Hidden; startInfo.Arguments = "http://www.google.com"; Process ieProcess = Process.Start(startInfo); 

Esto genera 2 procesos visibles en el Administrador de tareas de Windows. Luego, bash matar el proceso con:

 ieProcess.Kill(); 

Esto da como resultado que uno de los procesos en el Administrador de tareas se cierre y el otro permanezca. Intenté buscar propiedades que pudieran tener procesos secundarios, pero no encontré ninguna. ¿Cómo puedo matar el otro proceso también? De manera más general, ¿cómo matas a todos los procesos asociados con un proceso que comienzas con Process.Start?

Esto funcionó muy bien para mí:

 ///  /// Kill a process, and all of its children, grandchildren, etc. ///  /// Process ID. private static void KillProcessAndChildren(int pid) { // Cannot close 'system idle process'. if (pid == 0) { return; } ManagementObjectSearcher searcher = new ManagementObjectSearcher ("Select * From Win32_Process Where ParentProcessID=" + pid); ManagementObjectCollection moc = searcher.Get(); foreach (ManagementObject mo in moc) { KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"])); } try { Process proc = Process.GetProcessById(pid); proc.Kill(); } catch (ArgumentException) { // Process already exited. } } 

Actualización 2016-04-26

Probado en Visual Studio 2015 Update 2 en Win7 x64 . Todavía funciona tan bien ahora como lo hizo hace 3 años.

Actualización 2017-11-14

Comprobación adicional para el proceso inactivo del sistema if (pid == 0)

Actualización 2018-03-02

Necesita agregar una referencia al espacio de nombres System.Management , vea el comentario de @MinimalTech a continuación. Si tiene ReSharper instalado, ofrecerá hacer esto automáticamente.

Debe llamar a Process.CloseMainWindow() que enviará un mensaje a la ventana principal del proceso. Piense que el usuario tiene que hacer clic en el botón de cerrar “X” o Archivo | Salir del elemento del menú.

Es más seguro enviar un mensaje a Internet Explorer para que se cierre, que ir y matar a todos sus procesos. Esos procesos podrían estar haciendo cualquier cosa y debes dejar que IE haga lo suyo y terminar antes de matarlo mientras haces algo que puede ser importante para futuras tiradas. Esto se aplica a cualquier progtwig que mates.

No soy fan de ninguna de las soluciones presentadas aquí.

Esto es lo que se me ocurrió:

 private static void EndProcessTree(string imageName) { Process.Start(new ProcessStartInfo { FileName = "taskkill", Arguments = $"/im {imageName} /f /t", CreateNoWindow = true, UseShellExecute = false }).WaitForExit(); } 

Cómo utilizar:

 EndProcessTree("chrome.exe"); 
  • Clase de proceso (System.Diagnostics)
  • Clase ProcessStartInfo (System.Diagnostics)
  • Taskkill

Si alguien está interesado, tomé una de las respuestas de la otra página y la modifiqué ligeramente. Es una clase autónoma ahora con métodos estáticos. No tiene un manejo o registro de errores adecuado. Modificar para usar para sus propias necesidades. Proporcionar su proceso de raíz a KillProcessTree lo hará.

 class ProcessUtilities { public static void KillProcessTree(Process root) { if (root != null) { var list = new List(); GetProcessAndChildren(Process.GetProcesses(), root, list, 1); foreach (Process p in list) { try { p.Kill(); } catch (Exception ex) { //Log error? } } } } private static int GetParentProcessId(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; } private static void GetProcessAndChildren(Process[] plist, Process parent, List output, int indent) { foreach (Process p in plist) { if (GetParentProcessId(p) == parent.Id) { GetProcessAndChildren(plist, p, output, indent + 1); } } output.Add(parent); } } 

Otra solución es usar el comando taskill. Uso el siguiente código en mis aplicaciones:

 public static void Kill() { try { ProcessStartInfo processStartInfo = new ProcessStartInfo("taskkill", "/F /T /IM your_parent_process_to_kill.exe") { WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, WorkingDirectory = System.AppDomain.CurrentDomain.BaseDirectory, RedirectStandardOutput = true, RedirectStandardError = true }; Process.Start(processStartInfo); } catch { } } 

Si alguien necesita una solución de núcleo dotnet, dotnet cli se le ocurrió una implementación basada en taskill como se mencionó anteriormente y pgrep / kill recursivo para sistemas basados ​​en Unix. La implementación completa se puede encontrar en github . Lamentablemente, la clase es interna, por lo que tendrás que copiarla en tu código base.

Lista de procesos secundarios (tiene que hacerse recursivamente):

 $"pgrep -P {parentId}" 

Matar en el proceso:

 $"kill -TERM {processId}" 

¿Estás usando IE8 o IE9? Eso definitivamente iniciaría más de un proceso debido a su nueva architecture multiproceso. De todos modos, eche un vistazo a esta otra respuesta para obtener un árbol de proceso y matarlo.

Otro enfoque que puede ser muy útil es usar la API de Windows para objetos de trabajo . Se puede asignar un proceso a un objeto de trabajo. Los procesos secundarios de dicho proceso se asignan automáticamente al mismo objeto de trabajo.

Todos los procesos asignados a un objeto de trabajo se pueden matar de una vez, por ejemplo, con TerminateJobObject, que:

Termina todos los procesos actualmente asociados con el trabajo.

El ejemplo de C # en esta respuesta ( basado en esta respuesta ) utiliza en su lugar el indicador JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE , que:

Hace que todos los procesos asociados con el trabajo finalicen cuando se cierra el último identificador del trabajo.

¿Cómo cerrar adecuadamente Internet Explorer cuando se inicia desde PowerShell?

Varios de ellos comentaron en el hilo anterior que esto es causado por un error en Win7 (ya que no parece ocurrir para los usuarios que están usando otras versiones de Windows). Muchas páginas en Internet, incluida la página de Microsoft, reclaman un error de usuario, y le dicen que simplemente use el método de salida disponible en el objeto IE que también SUPONE para cerrar todos los procesos secundarios (y según se informa en Win8 / XP, etc.)

Debo admitir que, por mi parte, fue un error del usuario. Estoy en win7 y la razón por la cual el método de dejar de fumar no me funcionaba era por un error en la encoding. A saber, estaba creando el objeto IE en la statement, y luego creé otro (adjunto al mismo objeto) más adelante en el código … Casi había terminado de hackear la rutina de matar padre e hijo para trabajar para mí cuando me di cuenta del problema.

Debido a la forma en que funciona IE, el ID de proceso que engendró como padre se puede adjuntar a otras ventanas / subprocesos que NO creó. Use salir, y tenga en cuenta que, dependiendo de la configuración del usuario (como la memoria caché vacía al salir), los procesos podrían tardar unos minutos en terminar sus tareas y cerrarse.