Tuer l'arbre du processus de manière programmatique en C#

je commence Internet Explorer programmatically avec le code qui ressemble à ceci:

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

génère 2 Processus visibles dans le Gestionnaire des tâches Windows. Puis, je tente de tuer le processus avec:

ieProcess.Kill();

il en résulte que l'un des processus du Gestionnaire des tâches est arrêté et que l'autre est maintenu. J'ai essayé de vérifier toutes les propriétés qui auraient des processus enfants, mais j'en ai trouvé aucun. Comment puis-je tuer l'autre processus aussi? Plus généralement, comment tuer tous les processus associés à un processus que vous commencez avec le processus.Démarrer?

31
demandé sur Cœur 2011-05-05 21:17:10

9 réponses

cela a très bien fonctionné pour moi:

/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
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.
    }
}

mise à jour 2016-04-26

testé sur Visual Studio 2015 Update 2 sur Win7 x64 . Ça marche toujours aussi bien maintenant qu'il y a 3 ans.

mise à jour 2017-11-14

contrôle ajouté pour le processus de ralenti du système if (pid == 0)

mise à jour 2018-03-02

Besoin d'ajouter une référence à la System.Management espace de noms, voir le commentaire de @MinimalTech ci-dessous. Si vous avez ReSharper installé, il vous proposera de le faire automatiquement pour vous.

49
répondu Contango 2018-08-01 04:41:42

vous devez appeler Process.CloseMainWindow() qui enverra un message à la fenêtre principale du processus. Pensez - y comme si l'utilisateur avait cliqué sur le bouton "X" Fermer ou fichier | sortie élément de menu.

il est plus sûr d'envoyer un message à Internet Explorer pour se fermer, que d'aller tuer tous ses processus. Ces processus peuvent faire n'importe quoi et vous devez laisser IE faire son truc et finir avant de le tuer dans le au milieu de faire quelque chose qui pourrait être important pour les futures courses. Cela vaut pour tout programme que vous tuez.

10
répondu Kerry Kobashi 2016-03-08 15:39:06

Je ne suis fan d'aucune des solutions présentées ici.

voici ce que j'ai trouvé:

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

comment utiliser:

EndProcessTree("chrome.exe");
8
répondu Owen 2017-02-19 21:13:03

Si quelqu'un est intéressé, j'ai pris l'une des réponses de l'autre page et la modifier légèrement. C'est une classe avec des méthodes statiques. Il ne pas avoir la manipulation d'erreur appropriée ou la journalisation. Modifier pour l'utiliser pour vos propres besoins. Fournir votre processus root pour KillProcessTree le fera.

class ProcessUtilities
{
    public static void KillProcessTree(Process root)
    {
        if (root != null)
        {
            var list = new List<Process>();
            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<Process> output, int indent)
    {
        foreach (Process p in plist)
        {
            if (GetParentProcessId(p) == parent.Id)
            {
                GetProcessAndChildren(plist, p, output, indent + 1);
            }
        }
        output.Add(parent);
    }
}
7
répondu robr 2011-05-07 15:25:31

une autre solution consiste à utiliser la commande taskill. J'utilise le code suivant dans mes applications:

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 { }
}
6
répondu Juan Carlos Velez 2015-09-15 20:27:38

si quelqu'un a besoin d'une solution dotnet core, dotnet cli a développé une implémentation basée sur taskill comme mentionné ci-dessus et récursive pgrep/kill pour les systèmes basés sur unix. la Pleine mise en œuvre peut être trouvé sur github . Malheureusement, la classe est interne donc vous devrez la Copier dans votre base de code.

Liste des processus Enfants (doit être fait de manière récursive):

$"pgrep -P {parentId}"

Tuer sur le processus:

$"kill -TERM {processId}"
5
répondu Cyprien Autexier 2017-12-07 15:12:18

utilisez-vous IE8 ou IE9? Cela lancerait absolument plus d'un processus en raison de sa nouvelle architecture multi-processus. Quoi qu'il en soit, jetez un oeil à cette autre réponse pour obtenir un arbre de processus et le tuer.

4
répondu Matthew Ferreira 2017-05-23 12:26:34

une autre approche qui peut être très utile est d'utiliser L'API de Windows pour les objets de travail . Un processus peut être attribué à un objet de travail. Les processus enfants d'un tel processus sont automatiquement attribués à la même objet de travail.

tous les processus assignés à un objet de travail peuvent être tués à la fois, p.ex. avec Terminatejobject qui:

met fin à tous les processus actuellement associés à emploi.

le c# exemple dans cette réponse ( basé sur cette réponse ) utilise le JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE drapeau à la place, qui:

provoque la fin de tous les processus associés à l'emploi lorsque la dernière poignée vers l'emploi est fermée.

1
répondu Peter 2017-05-23 11:47:32

comment fermer correctement Internet Explorer lorsqu'il est lancé depuis PowerShell?

plusieurs de ceux qui ont commenté dans le thread ci-dessus que cela est causé par un bug dans Win7 (comme il ne semble pas se produire pour les utilisateurs qui utilisent d'autres versions de windows). Beaucoup de pages sur l'internet, y compris la page de microsoft revendication d'erreur de l'utilisateur, et vous dire d'utiliser simplement la méthode quit disponible sur L'objet IE qui est censé fermer tous les processus enfant comme bien (et, apparemment, n'en Win8/XP etc)

je dois admettre, pour ma part, que c'était une erreur de l'utilisateur. Je suis dans win7 et la raison pour laquelle la méthode d'abandon ne fonctionnait pas pour moi était en raison d'une erreur de codage. Plus précisément, je créais L'objet IE lors de la déclaration, puis j'en créais un autre (attaché au même objet) plus tard dans le code... J'avais presque fini de pirater la routine parent-enfant de tuer pour travailler pour moi quand j'ai réalisé le problème.

à cause de comment IE functions, le processID que vous avez généré comme parent peut être attaché à d'autres fenêtres/sous-processus que vous n'avez pas créés. Utilisez quit, et gardez à l'esprit que selon les paramètres de l'utilisateur (comme le cache vide à la sortie), les processus peuvent prendre quelques minutes pour terminer leurs tâches et fermer.

0
répondu Jack Hadley 2017-05-23 12:18:24