2015-05-15 16 views
9

Non riesco a utilizzare Process.Kill(). Penso che dovrei fraintendere come funziona. Questa è la mia funzione di test. Inizio un processo di lunga durata (ping -t) e poi lo uccido cinque secondi dopo.Process.Kill() non sembra terminare il processo

È possibile visualizzare il processo di ping, ma il processo è ancora lì dopo che il programma è terminato. Devo ucciderlo manualmente.

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); 

Cosa sto facendo di sbagliato qui?

+0

Testato il codice e funziona correttamente. Da dove stai eseguendo questo codice? – vesan

+0

@vesan Windows 8.1. L'ho eseguito sia da PowerShell che da cmd.exe. –

+0

Qualche differenza per eseguire direttamente Ping.exe senza cmd? –

risposta

9

Hai avviato cmd.exe, quindi cmd.exe avvia il processo figlio ping.exe. Per uccidere ping.exe è possibile eliminare tutta la gerarchia dei processi. Per esempio con WMI (aggiungere System.Management di riferimento):

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.) 
     } 
    } 
} 
+1

Cosa succede se il processo figlio genera un processo a sé stante? Avremmo bisogno di un modo per uccidere ricorsivamente l'intero albero, no? –

+0

In questo esempio di codice uccidiamo l'albero intero in modo ricorsivo. – SulNR

+0

Oh strano, devo averlo perso quando l'ho letto prima. Ti assegnerò la taglia. –

-1

Per terminare un processo è necessario eseguire un account amministrativo . Ciò significa che sei un amministratore "vero" o che hai il controllo dell'account utente (UAC) disattivato.

In caso contrario, Process.Kill() avrà esito negativo.

Da here.

+0

Lo proverò quando torno a casa, ma sono abbastanza sicuro di averlo già provato e non ha funzionato. Dovrebbe essere sufficiente per eseguire cmd.exe come amministratore e quindi chiamare il mio programma, giusto? –

+0

Ho provato a eseguire il mio programma di test in un prompt di amministrazione e ancora non sembra che il processo venga interrotto. –

0

process.Kill() funziona, solo non sul processo che si pensa. Quello che stai facendo in realtà è avviare 2 processi e uccidere solo il primo processo, mentre il secondo processo continua a funzionare. Il codice che hai sta iniziando una nuova shell di comando e salvando le informazioni di processo su process. Quando si chiama process.Kill() solo la shell di comando sta uscendo È possibile eseguire

Console.WriteLine(process.ProcessName); 

prima process.Kill() di vedere quale processo è in realtà sta per essere ucciso. Impostando \c ping -t 8.8.8.8 come argomenti sulla shell dei comandi, si dice alla shell dei comandi di avviare un altro processo (in questo caso ping) e di disconnetterlo da se stesso. Il tuo programma non ha conoscenza del processo figlio e non lo ucciderà. Se tutto quello che vuole veramente è quello di uccidere il processo di ping è possibile modificare il codice per:

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); 

Se, tuttavia, si ha realmente bisogno per avviare la shell di comando in primo luogo è necessario trovare i processi figli e hanno logica ucciderlo. Qualcosa di simile:

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

[EDIT] * Ci dispiace, non ho visto i commenti da @Adriano Repetti in un primo momento. Non volevo essere ridondante.

0

Si tratta di una patch per la @SulNR risposta dal momento che sua risposta processi di perdita figlio di processi figli.

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. 
    } 
}