web-dev-qa-db-fra.com

Process.Kill () ne semble pas tuer le processus

J'ai des problèmes pour utiliser Process.Kill(). Je pense que je dois mal comprendre comment cela fonctionne. Ceci est ma fonction de test. Je lance un processus long (ping -t) puis je le tue cinq secondes plus tard.

Je peux voir le processus de ping apparaître, mais le processus est toujours là après la fin de mon programme. Je dois le tuer manuellement.

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);

ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe");
Process process = new Process();

startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = "/c ping -t 8.8.8.8";

Console.WriteLine("Staring ping process");
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);
Thread.Sleep(5000);

Console.WriteLine("Killing ping process");
process.Kill();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);

Qu'est-ce que je fais mal ici?

12
Kris Harper

Vous avez démarré cmd.exe, puis cmd.exe lance le processus enfant ping.exe. Pour tuer ping.exe, vous pouvez tuer toutes les hiérarchies de processus. Par exemple avec WMI (ajoutez la référence System.Management):

private static void KillProcessAndChildrens(int pid)
{
    ManagementObjectSearcher processSearcher = new ManagementObjectSearcher
      ("Select * From Win32_Process Where ParentProcessID=" + pid);
    ManagementObjectCollection processCollection = processSearcher.Get();

    try
    {
        Process proc = Process.GetProcessById(pid);
        if (!proc.HasExited) proc.Kill();
    }
    catch (ArgumentException)
    {
        // Process already exited.
    }

    if (processCollection != null)
    {
        foreach (ManagementObject mo in processCollection)
        {
            KillProcessAndChildrens(Convert.ToInt32(mo["ProcessID"])); //kill child processes(also kills childrens of childrens etc.)
        }
    }
}
16
SulNR

Ceci est un correctif pour @SulNR answer car sa réponse bloque les processus enfants des processus enfants.

private static void KillProcessAndChildrens(int pid)
{
    ManagementObjectSearcher processSearcher = new ManagementObjectSearcher
      ("Select * From Win32_Process Where ParentProcessID=" + pid);
    ManagementObjectCollection processCollection = processSearcher.Get();

    // We must kill child processes first!
    if (processCollection != null)
    {
        foreach (ManagementObject mo in processCollection)
        {
            KillProcessAndChildrens(Convert.ToInt32(mo["ProcessID"])); //kill child processes(also kills childrens of childrens etc.)
        }
    }

    // Then kill parents.
    try
    {
        Process proc = Process.GetProcessById(pid);
        if (!proc.HasExited) proc.Kill();
    }
    catch (ArgumentException)
    {
        // Process already exited.
    }
}
3
Julio

process.Kill () fonctionne, mais pas sur le processus que vous pensez. En réalité, vous démarrez deux processus et ne supprimez que le premier processus, tandis que le deuxième processus continue de s'exécuter. Le code que vous avez commence une nouvelle commande Shell et enregistre les informations relatives à ce processus dans process. Lorsque vous appelez process.Kill(), seule la commande Shell est en cours de sortie. Vous pouvez exécuter 

Console.WriteLine(process.ProcessName);

avant process.Kill() pour voir quel processus va être tué. En définissant \c ping -t 8.8.8.8 comme arguments de la commande Shell, vous indiquez à la commande Shell de démarrer un autre processus (dans ce cas, ping) et de le disjoindre de lui-même. Votre programme n'a aucune connaissance du processus enfant et ne le supprimera pas. Si tout ce que vous voulez, c'est de tuer le processus ping, vous pouvez changer votre code en:

Console.WriteLine("Total number of ping processes is {0}",  Process.GetProcessesByName("ping").Length);

ProcessStartInfo startInfo = new ProcessStartInfo("ping");
Process process = new Process();

startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = "-t 8.8.8.8";

Console.WriteLine("Staring ping process");
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);
Thread.Sleep(5000);

Console.WriteLine("Killing ping process");
process.Kill();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);

Si, toutefois, vous devez réellement lancer la commande Shell d’abord, vous devez trouver les processus enfants et disposer d’une logique pour le supprimer. Quelque chose comme:

foreach( var p in Process.GetProcessesByName("ping"))
{
  p.Kill();
}

[EDIT] * Désolé, je n'ai pas vu les commentaires de @Adriano Repetti au début. Je ne voulais pas être redondant.

0
rogergarrison