Process.Kill() doesn't seem to kill the process - c#

I am having trouble using Process.Kill(). I think I must be misunderstanding how it works. This is my test function. I start a long-running process (ping -t) and then kill it five seconds later.
I can see the ping process show up, but the process is still there after my program finishes. I have to kill it manually.
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);
What am I doing wrong here?

You started cmd.exe, then cmd.exe starts child process ping.exe. To kill ping.exe you can kill all process hierarchy. For example with WMI(add System.Management reference):
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.)
}
}
}

This is a patch for the #SulNR answer since its answer leak child processes of child processes.
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.
}
}

process.Kill() is working, just not on the process you think. What you're doing is actually starting 2 processes and only killing the first process, while the second process keeps running.
The code you have is starting a new command shell and saving that process info to process. When you call process.Kill() only the command shell is exiting You can run
Console.WriteLine(process.ProcessName);
before you process.Kill() to see which process is actually going to be killed. By setting \c ping -t 8.8.8.8 as arguments to the command shell, you're telling the command shell to start another process (in this case ping) and disjoin it from itself. Your program has no knowledge about the child process and will not kill it. If all you really want is to kill the ping process you can change your code to:
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);
If, however, you really need to start the command shell first you'll need to find the child processes and have logic to kill that. Something like:
foreach( var p in Process.GetProcessesByName("ping"))
{
p.Kill();
}
[EDIT]
*Sorry, I didn't see the comments from #Adriano Repetti at first. I didn't mean to be redundant.

FWIW a VS2019 Visual Basic version of Julio's modification.
Private Sub KillProcessAndChildrens(pintPID As Integer)
Dim processSearcher As New ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pintPID.ToString)
Dim processCollection As ManagementObjectCollection = processSearcher.Get()
' We must kill child processes first!
If Not IsNothing(processCollection) Then
For Each mo As ManagementObject In processCollection
KillProcessAndChildrens(Convert.ToInt32(mo.Item("ProcessID")))
Next
End If
' // Then kill parents.
Try
Dim proc As Process = Process.GetProcessById(pintPID)
If Not proc.HasExited Then
proc.Kill()
End If
Catch ex As Exception
' Process already exited.
End Try
End Sub

It's very simple:
foreach (var process in Process.GetProcessesByName(processName))
{
try
{
process.Kill();
}
catch { }
}
With this method, you can also kill processes with a higher protection level like taskmgr.exe. If you want to prevent a process from starting, here is a piece of code suitable for that, at least as long as the process running this code is active:
private void Disable(string processName)
{
var timer = new Timer()
{
Interval = 1,
Enabled = true
};
timer.Tick += (s, e) =>
{
foreach (var process in Process.GetProcessesByName(processName))
{
try
{
process.Kill();
}
catch { }
}
GC.Collect();
};
}

In order to kill a process you have to run under an administrative
account. This means either that you are a 'true' administrator or you
User Account Control (UAC) turned off.
Otherwise Process.Kill() will fail.
From here.

Related

Process Id is changed while running the process

I am using System.Diagnostics in c#. My problem is I am using code for starting and killing the process in c# and it's working fine. But my question is my process id is changing in-between while running the process. Is that possible. If yes then how can I get the actual process id which I want to kill. I can't do it by name because I have multiple instance are running on different at a time and I want to kill only single instance on started port.
My code is :
Process p2 = new Process();
ProcessStartInfo processStartInfo2 =
new ProcessStartInfo(
unitoolLauncherExePath,
"options --port " + port);
p2.StartInfo = processStartInfo2;
p2.Start();
System.Threading.Thread.Sleep(1000);
int processId = p2.Id;
Now it will return something like 14823 and when I am trying to kill it it's changed.
Process[] _proceses = null;
_proceses = Process.GetProcessesByName("UNIToolAPIServer");
foreach (Process proces in _proceses)
{
if (proces.Id == processId)
{
proces.Kill();
}
}
But here nothing is killed because no process with the above id is fetched.
No, the process id of a running process does not change while it is running.
If there is no process to kill with the process id of the process you started, it means either of two things:
The process has already exited before you obtain the process list.
The name of the process is not "UNIToolAPIServer".
If you want to kill the created process you should keep the process-object and call the kill method on it. There should be no need to go thru all the processes in the system to find the started process. For example:
public class MyProcess{
private Process myProcess;
...
public void Start(){
myProcess = new Process();
var processStartInfo2 = new ProcessStartInfo(
unitoolLauncherExePath,
"options --port " + port);
myProcess.StartInfo = processStartInfo2;
myProcess.Start();
}
public void Kill(){
if(myProcess != null && !myProcess.HasExited){
myProcess.Kill();
}
}
}

How to kill a process that have been forked?

I'm trying to start a process, here calc.exe, waiting X seconds, and kill it:
Process p = Process.Start("calc.exe");
Console.WriteLine(p.Id);
Thread.Sleep(3000);
p.Kill();
When i execute this code, output give me the PID of the new process (e.g. 7152), BUT after sleep, the Kill() doesn't work, it says the process is not running anymore. BUT i saw the calc still running, i can use it.
When i look in details of task manager, the PID of calc.exe is not the same than the previous... why?
How can i kill the process i've created? (calc.exe is just an example, but it could be a.txt, b.word...)
Thanks and sorry for my english! :)
Are you sure about the pid changing? what happens if you compare it using
Process[] p = Process.GetProcessesByName( "calc.exe" );
foreach(var proc in p)
Console.WriteLine("Found: "+proc.Id == myExpectedProcId);
After you have the pid here is a hacky way to kill it
/// <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.
}
}

Process,Kill() Not Working

I'm trying to make a service, that every 1000milliseconds(1 Second) Kills any process with the name Skype. I'm 100% sure I have coded it all correctly, everything is working, logging etc. But killing the process is not.
private System.Timers.Timer _timer;
protected override void OnStart(string[] args)
{
try
{
_timer = new System.Timers.Timer(100);
_timer.Elapsed += _timer_Elapsed;
_timer.Enabled = true;
if (!EventLog.SourceExists("MYTESTSERVICE"))
EventLog.CreateEventSource("MYTESTSERVICE", "MYTESTSERVICE LOG");
//_timer.Start();
Process[] p = Process.GetProcessesByName("Skype");
foreach (Process proc in p)
{
proc.Kill();
proc.WaitForExit();
EventLog.WriteEntry("User Tried To Start Skype! Closed.", EventLogEntryType.Warning);
}
}
catch (Exception ex)
{
EventLog.WriteEntry(String.Format("WcfServiceHostTest \n Exception Message: {0}\nTrace: {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
}
}
I am currently not using the timer, but instead testing it upon service startup. If Skype is running, the process is not killed. I even tried notepad, and it did not kill that either. I have done research on this, but have not found an answer.
Any help is appreciated!
- Seb
you can use the taskkill:
Process.Start(new ProcessStartInfo
{
FileName = "taskkill",
Arguments = $"/im skype.exe /f /t",
CreateNoWindow = true,
UseShellExecute = false
}).WaitForExit();

Restart an application by itself

I want to build my application with the function to restart itself. I found on codeproject
ProcessStartInfo Info=new ProcessStartInfo();
Info.Arguments="/C choice /C Y /N /D Y /T 3 & Del "+
Application.ExecutablePath;
Info.WindowStyle=ProcessWindowStyle.Hidden;
Info.CreateNoWindow=true;
Info.FileName="cmd.exe";
Process.Start(Info);
Application.Exit();
This does not work at all...
And the other problem is, how to start it again like this?
Maybe there are also arguments to start applications.
Edit:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=31454&av=58703
I use similar code to the code you tried when restarting apps. I send a timed cmd command to restart the app for me like this:
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 2 && \"" + Application.ExecutablePath + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Application.Exit();
The command is sent to the OS, the ping pauses the script for 2-3 seconds, by which time the application has exited from Application.Exit(), then the next command after the ping starts it again.
Note: The \" puts quotes around the path, incase it has spaces, which cmd can't process without quotes.
Hope this helps!
Why not use
Application.Restart();
??
More on Restart
Why not just the following?
Process.Start(Application.ExecutablePath);
Application.Exit();
If you want to be sure the app does not run twice either use Environment.Exit(-1) which kills the process instantaneously (not really the nice way) or something like starting a second app, which checks for the process of the main app and starts it again as soon as the process is gone.
You have the initial application A, you want to restart.
So, When you want to kill A, a little application B is started, B kill A, then B start A, and kill B.
To start a process:
Process.Start("A.exe");
To kill a process, is something like this
Process[] procs = Process.GetProcessesByName("B");
foreach (Process proc in procs)
proc.Kill();
A lot of people are suggesting to use Application.Restart. In reality, this function rarely performs as expected. I have never had it shut down the application I am calling it from. I have always had to close the application through other methods such as closing the main form.
You have two ways of handling this. You either have an external program that closes the calling process and starts a new one,
or,
you have the start of your new software kill other instances of same application if an argument is passed as restart.
private void Application_Startup(object sender, StartupEventArgs e)
{
try
{
if (e.Args.Length > 0)
{
foreach (string arg in e.Args)
{
if (arg == "-restart")
{
// WaitForConnection.exe
foreach (Process p in Process.GetProcesses())
{
// In case we get Access Denied
try
{
if (p.MainModule.FileName.ToLower().EndsWith("yourapp.exe"))
{
p.Kill();
p.WaitForExit();
break;
}
}
catch
{ }
}
}
}
}
}
catch
{
}
}
Winforms has the Application.Restart() method, which does just that. If you're using WPF, you can simply add a reference to System.Windows.Forms and call it.
Another way of doing this which feels a little cleaner than these solutions is to run a batch file which includes a specific delay to wait for the current application to terminate. This has the added benefit of preventing the two application instances from being open at the same time.
Example windows batch file ("restart.bat"):
sleep 5
start "" "C:\Dev\MyApplication.exe"
In the application, add this code:
// Launch the restart batch file
Process.Start(#"C:\Dev\restart.bat");
// Close the current application (for WPF case)
Application.Current.MainWindow.Close();
// Close the current application (for WinForms case)
Application.Exit();
My solution:
private static bool _exiting;
private static readonly object SynchObj = new object();
public static void ApplicationRestart(params string[] commandLine)
{
lock (SynchObj)
{
if (Assembly.GetEntryAssembly() == null)
{
throw new NotSupportedException("RestartNotSupported");
}
if (_exiting)
{
return;
}
_exiting = true;
if (Environment.OSVersion.Version.Major < 6)
{
return;
}
bool cancelExit = true;
try
{
List<Form> openForms = Application.OpenForms.OfType<Form>().ToList();
for (int i = openForms.Count - 1; i >= 0; i--)
{
Form f = openForms[i];
if (f.InvokeRequired)
{
f.Invoke(new MethodInvoker(() =>
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}));
}
else
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}
if (cancelExit) break;
}
if (cancelExit) return;
Process.Start(new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Application.ExecutablePath,
Arguments = commandLine.Length > 0 ? string.Join(" ", commandLine) : string.Empty
});
Application.Exit();
}
finally
{
_exiting = false;
}
}
}
This worked for me:
Process.Start(Process.GetCurrentProcess().MainModule.FileName);
Application.Current.Shutdown();
Some of the other answers have neat things like waiting for a ping to give the initial application time to wind down, but if you just need something simple, this is nice.
For .Net application solution looks like this:
System.Web.HttpRuntime.UnloadAppDomain()
I used this to restart my web application after changing AppSettings in myconfig file.
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
configuration.AppSettings.Settings["SiteMode"].Value = model.SiteMode.ToString();
configuration.Save();

Close windows application

is it possible to close a running application with another application?
I have implemented APP1.exe and APP1_UNIN.exe, I would that APP1_UNIN.exe kill running APP1.exe and uninstall it.
Is it possible?
To uninstall an application, you can start a new process and invoke msiexec.exe, and on the command line you can specify what to uninstall:
ProcessStartInfo psi;
//take your choice of which you want to use:
psi = new ProcessStartInfo("msiexec.exe", string.Format("/x {0}", "path of my msi"));
psi = new ProcessStartInfo("msiexec.exe", string.Format("/x /n {{{0}}}", "my product code"));
Process p = new Process();
p.StartInfo = psi;
p.Start();
Use System.Diagnostics.Process class:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.closemainwindow(v=VS.71).aspx
There's also a Kill method.
At least to kill the running process you can do like this:
Process[] processes = Process.GetProcesses();
foreach (Process process in processes) {
if (process.ProcessName == "APP1.exe") {
try {
process.Kill();
break;
} catch (Exception) {
//handle any exception here
}
}
}
}
Regarding uninstalling it, I'm not sure.
For closing, you can do it by killing its process. System.Diagnostics.Process
Process []pArray = Process.GetProcesses();
foreach(Process prc in pArray) {
string s = prc.ProcessName;
if (s.CompareTo("APP1") ==0) {
prc.Kill();
}
}
Yes using System.Diagnostics
You can get the process and Kill the Process.

Categories