I am trying to test the following code snippet.
static void StartAndKill()
{
Process ieProc = Process.Start("iexplore.exe", "www.apress.com");
Console.WriteLine("--> Hit enter to kill {0}\t", ieProc.ProcessName);
Console.ReadLine();
try
{
Console.WriteLine(ieProc.Id);
ieProc.Kill();
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
This should kill the internet explorer window and close it. Instead I get an exception that says:
Cannot process request because the process (7256) has exited.
What is the logical explanation for this behaviour?
If the iexplore process is already running (check Task Manager), then Process.Start may use the existing process - but the process id you get back is not for this existing process, but a dummy process that starts and then exits. You could enumerate the existing iexplore processes and check their titles to find the correct one, and then get its process id and kill it.
The error message is misleading. The real reason why the process doesn't get killed is administrative privs on Windows 7 are not defaulted. If I open a command prompt by using "Run as administrator", the code does what it is supposed to do. I will move to close this question.
Thanks to all those who responded.
Related
Suppose I have an Application.exe running on Windows. I want to log "My process was killed.", if someone else kills my process using task manager etc. How can I get the process closure information? Search results did not return any useful information. I am interested in C# and Windows solutions.
System.Diagnostics.Process class has an ExitCode property. But if process is already killed, how can i even use it?
I have a strange behaviour when I try to start explorer.exe from c# like this:
ProcessStartInfo info = new ProcessStartInfo("explorer.exe", "E:");
info.WindowStyle = ProcessWindowStyle.Hidden;
Process process = new Process();
process.StartInfo = info;
process.Start();
Thread.Sleep(2000);
bool res = process.CloseMainWindow(); // InvalidOperationException -> already exited
process.Close();
process.WaitForExit(5000);
The problem is:
the exception seems correct, because at this point HasExited returns already true. Nevertheless in the taskmanager the created instance of explorer is still present.
So I dont understand what my call does. I had thought it would directly start an instance of explorer, but it seems not or the explorer works in some different way.
And my second question: how can I start and shortly after that stop a new specific instance of explorer programmatically?
Edit
to answer some questions:
explorer option Launch Folder Windows in a separate process is set to true
the created process.Id is not present in taskmanager. For example: the new explorer instance shown in taskmanager has PID 4968 while the debugger shows 10752 as ID of the created (and exited) process.
Edit: here a screenshot from taskmanager after ~12 debug runs
This may be down to the fact that the explorer.exe process in question HAS exited. Windows does some strange things with multiple explorer windows and it depends on the options you have set. By default, all windows end up running in a single process if I remember correctly.
What I would do is output the processid for the process you just generated:
Console.WriteLine($"{process.Id} has exited {process.HasExited}");
Then look at task manager to see if you can find the corresponding process. I would imagine that the HasExited is true so you won't find the process, but the window will have opened.
You may have to set process.EnableRaisingEvents to true to get a valid answer from process.HasExited, I can't recall of the top of my head.
Also check the setting in Explorer via Folder Options to see if you have Launch Folder Windows in a separate process enabled or not on the view tab.
IF you do find your process, you can always kill off that process and see if your windows closes. If it does, then it may be that the explorer.exe is not creating a main window handle which you can check using Spy++
Edited with more info
Further more, #Hans Passant mentioned above that shell windows work different. So what actually happens is this, explorer.exe (1234) contacts the root explorer.exe (321), which in turn then creates a new window (if Launch separate is false) or spawns a subprocess explorer.exe (3445). Your process explorer.exe (1234) having done its job, then exits. No window is ever created by your process so CloseMainWindow() will not find a window to close and errors.
How to close a specific explorer window
To do so you need to utilise ShellWindows, see Is there a way to close a particular instance of explorer with C#?
For reference the code used there was:
ShellWindows _shellWindows = new SHDocVw.ShellWindows();
string processType;
foreach (InternetExplorer ie in _shellWindows)
{
//this parses the name of the process
processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
//this could also be used for IE windows with processType of "iexplore"
if (processType.Equals("explorer") && ie.LocationURL.Contains(#"C:/Users/Bob"))
{
ie.Quit();
}
}
Note, you need to be careful that you aren't closing a window the user wanted open in the first place. Is there a reason to close the window?
The problem is in the notion of has UI Interface, As per definition:
Closes a process that has a user interface by sending a close message
to its main window.
However explorer.exe is far more complicated than a simple process with UI.
If for example you use another, application, more simple (e.g Notepad), no exception will be raised:
ProcessStartInfo info = new ProcessStartInfo("notepad.exe");
info.WindowStyle = ProcessWindowStyle.Maximized;
Process process = new Process();
process.StartInfo = info;
process.Start();
Thread.Sleep(2000);
bool res = process.CloseMainWindow(); // InvalidOperationException -> already exited
process.Close();
I am running an executable that opens a windows form from a webform. In visual studio the winform program runs a method and then closes the windows form correctly and shuts down the program. But when I run the same file as an executable it keeps the windows form open. I can see that this executable process is still running as SmartSheetAPI.exe.
When I check in properties the name of the file is "SmartSheetAPI.exe". If I end this process in the task manager it shuts down the windows form so I know that is the issue. However, I have tried using the below code on the webform to kill the process but again it doesn't work.
Process process = new Process();
process.StartInfo.FileName = #"P:\Visual Studio 2013\Projects\Smartsheet\SmartsheetAPI\obj\Debug\SmartSheetAPI.exe";
process.Start();
foreach (var processes in Process.GetProcessesByName("SmartSheetAPI.exe"))
{
process.Kill();
}
Does anyone know how to shut this thing down. As I say it works well in the SmartSheetAPI program in visual studio but doesn't shutdown the window as an executable. I just need to shut down this process once it has run the method.
EDIT:
The process that isn't closing is the vshost.exe and as such it is keep my application from closing for some reason (i.e. the windows form remains open). If I process.kill() this everything shuts down as required. However, the problem is that when I run the executable of that file the windows form stays open but I can't find the vshost.exe running to close it? I have disabled it and now the process that won't close is the SmartSheetAPI.exe file which is the program I am currently running. I just want to exit out of this program, but nothing I try seems to work.
After calling the Kill method, call the WaitForExit method to wait for the process to exit, or check the HasExited property to determine if the process has exited.
Process process = new Process();
process.StartInfo.FileName = #"P:\Visual Studio 2013\Projects\Smartsheet\SmartsheetAPI\obj\Debug\SmartSheetAPI.exe";
process.Start();
// do some stuff while process is alive ...
process.Kill();
process.WaitForExit();
// do stuff after the process has been killed ...
For more details see here: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.kill(v=vs.110).aspx
If your process cannot be killed it is probably waiting for something else. You might want to investigate that rather than forcing your application to be terminated.
i am trying to start a browser instance as a process from a c# code. then i want to kill the same instance of the browser. I tried finding the same instance with process id . But the process ids are different in task manager and the initial id which i got when i started the process.
what's the solution? why is this happening? Development enviorment is windows 7.
int ID= 0;
void Start()
{
ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
ID= ieProcess.Id;
}
void Stop()
{
foreach (Process p in System.Diagnostics.Process.GetProcessesByName("iexplore"))
{
if ((p.Id == ID))
{
p.Kill();
}
}
This code will not work if IE is already launched. Close all IE browsers and then try to run the code. If it works then you may have to look for solution suggested in following link
similar post-
Process.kill() denied in Windows 7 32bits even with Administrator privileges
Why don't you add your code to the question? It'll make life easy for the people who are interested in helping you. If you get different PIDs, most probably there's something wrong with your code! (I'm just guessing without seeing what you have tried.)
Have a look at these questions as well.
1) Getting PID of process started by Process.start()
2) Programmatically kill a process in vista/windows 7 in C#
3) Process.kill() denied in Windows 7 32bits even with Administrator privileges
Adding the code makes it much easier to understand what the problem is and here's your problem.
IE creates more than one process for one instance of the program. (more details about it) That's why you get different PIDs (for the different processes).
What your code does is killing only one process of it (by the usage of if condition in the Stop() method!). So the remaining process may generate InvalidOperationException when you try to execute Start() again(starting the same process)!
So what your code should do is kill all the active iexplore processes. This can be done by simply removing the if condition of Stop() method.
foreach(Process p in Process.GetProcessesByName("iexplore"))
{
p.Kill();
}
Let me know whether this worked.
I have a similar issue, only I dont want to kill the IE process that I started, I want to bring it into focus.
I have one app that starts 5 IE windows.(not tabs, but unique windows)
I store the PIDs that I start each of the IE windows with.
At particular times, I want to be able to:
select a PID,
find the IE window related to that PID
bring it into focus (minimizing the others)
This worked using XP and IE6 (required for the environment)
Now when I am using Win 7 and IE 8, the PID that I stored is not found,
and thus I no longer have the ability to change the window in focus.
I am writing a program (Visual Studio 2010 in C# Windows Forms) which keeps track of multiple instances of the Remote Desktop Client (mstsc.exe - tested with Windows 7 version). I have been attempting to launch this program and grab its PID with the following code:
Process mstsc = Process.Start(mstscLocation, mstscConString);
int mstscProcessId = mstsc.Id;
DataRow row = openConn.NewRow();
row["RDP ID"] = mstscID;
openConn.Rows.Add(row);
This starts the client and returns an ID as it should. Problem is, if I try to terminate the PID with the following code, it fails to do so:
int rdpID = Convert.ToInt32(dgvOpenConnections.Rows[selectedIndex].Cells["RDP ID"].Value.ToString());
try
{
// kill off mstsc
Process mstsc = Process.GetProcessById(rdpID);
mstsc.Kill();
}
I have verified that the PID that is recorded from Process.Start is the same as is retrieved from the DataGridView (dgvOpenConnections) and placed into rpdID (try fails and hits catch as the original PID no longer exists). Furthermore, I have issued a "tasklist" at a command prompt after starting one instance of MSTSC.EXE and can verify that it changes PIDs (in this test, C# recorded 4288 but tasklist shows it running as 8172).
I cannot kill all MSTSC processes as I am trying to control more than one. Is there a way to trace down the second PID MSTSC appears to use? My guess is it either starts a second process and gets rid of the first or maybe this is a child process (although the PID that is return no longer exists after start).
How in C# can I ensure I have the right process ID to later monitor or kill a specific instance of the Remote Desktop Client?
This happens if you try to run mstsc from a 32-bit application in 64-bit Windows.
(Source: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/22c10140-a502-4aa1-98d3-3607b8b573e8/)
There are two versions of mstsc on a 64-bit Windows:
c:\windows\system32\mstsc.exe is a 64-bit version
c:\windows\syswow64\mstsc.exe is more or less a "redirect" that will open c:\windows\system32\mstsc.exe from a different process than your application.
I've had the same issue. My application started mstsc, the process immediately exited, and mstsc reappeared with a different parent process and different PID.
This happens because 64-bit Windows uses file system redirection to redirect calls to the 64-bit c:\windows\system32 executables to c:\windows\syswow64.
There are two solutions:
Recompile your application to 64-bit. Then your application will also use the 64-bit mstsc.
Disable file system redirection (see http://blog.tonycamilli.com/2005/07/disabling-wow64-file-system.html) and access the 64-bit mstsc from your 32-bit application.
I have only tried recompiling, and it worked. :-)
Edit:
If you don't want your users to use the right version (we're using ClickOnce deployment, so we'd rather send one link to everybody), here's a workaround:
If you're using an .RDP file for mstsc, just add a unique token to your file name. mstsc will be started with a command line like mstsc host_user_token.rdp.
Now, after you called Process.Start, do Process.WaitForExit with a short timeout (5s). If the process did not exit, you have the right object.
If the process did exit, do a little polling loop (100ms interval, 5s timeout) that checks for processes with your token:
var timeout = AppSettings.GetIntValue(
Constants.SettingsKeyProcessFinderTimeout, Constants.ProcessFinderTimeoutDefault);
int elapsedTime = 0;
Process process = null;
while (elapsedTime <= timeout)
{
process =
Process.GetProcessesByName("mstsc").FirstOrDefault(p => p.StartInfo.Arguments.Contains(guid));
Logger.TraceVerbose(
string.Format(
"Elapsed time: {0}; Found process with PID {1}", elapsedTime, process == null ? -1 : process.Id));
if (process != null)
{
break;
}
Thread.Sleep(SleepInterval);
elapsedTime += SleepInterval;
}
After that loop, if you still have process == null, there was some error (process was not found or never executed at all). If you have a Process reference, that's the "new" mstsc process.
I tried your example using Process Explorer, and I couldn't see a second or child process being created. From beginning to end the Remote Desktop Process was one and the same, and after being created I was able to kill the process using the same PID I saw in the beginning.