Reputation: 21947
This code runs as expected on a large number of machines. However on one particular machine, the call to WaitForExit()
seems to be ignored, and in fact marks the process as exited.
static void Main(string[] args)
{
Process proc = Process.Start("notepad.exe");
Console.WriteLine(proc.HasExited); //Always False
proc.WaitForExit(); //Blocks on all but one machines
Console.WriteLine(proc.HasExited); //**See comment below
Console.ReadLine();
}
Note that unlike a similar question on SO, the process being called is notepad.exe
(for testing reasons), so it is unlikely the fault lies with it - i.e. it is not spawning a second sub-process and closing. Even so, it would not explain why it works on all the other machines.
On the problem machine, the second call to Console.WriteLine(proc.HasExited))
returns true
even though notepad is still clearly open, both on the screen and in the task manager.
The machine is running Windows 7 and .NET 4.0.
My question is; what conditions on that particular machine could be causing this? What should I be checking?
Edit - Things I've tried so far / Updates / Possibly relevant info:
GetProcessesByName
but that simply returns an empty array on the problem machine. Therefore, it's hard to say the problem is even with WaitForExit
, as the process is not returned by calling GetProcessesByName
even before calling WaitForExit
.Upvotes: 15
Views: 3443
Reputation: 51369
The problem is that by default Process.StartInfo.UseShellExecute is set to true. With this variable set to true, rather than starting the process yourself, you are asking the shell to start it for you. That can be quite useful- it allows you to do things like "execute" an HTML file (the shell will use the appropriate default application).
Its not so good when you want to track the application after executing it (as you found), because the launching application can sometimes get confused about which instance it should be tracking.
The inner details here of why this happens are probably beyond my capabilities to answer- I do know that when UseShellExecute == true, the framework uses the ShellExecuteEx Windows API, and when it UseShellExecute == false, it uses CreateProcessWithLogonW, but why one leads to trackable processes and the other doesn't I don't know, as they both seem to return the process ID.
EDIT: After a little digging:
This question pointed me to the SEE_MASK_NOCLOSEPROCESS flag, which does indeed seem to be set when using ShellExecute. The documentation for the mask value states:
In some cases, such as when execution is satisfied through a DDE conversation, no handle will be returned. The calling application is responsible for closing the handle when it is no longer needed.
So it does suggest that returning the process handle is unreliable. I still have not gotten deep enough to know which particular edge case you might be hitting here though.
Upvotes: 7
Reputation: 31743
A cause could be a virus that replaced notepad.exe to hide itself. If executed, it spawns notepad and exits (just a guess).
try this code:
var process = Process.Start("notepad.exe");
var process2 = Process.GetProcessById(process.Id);
while (!process2.HasExited)
{
Thread.Sleep(1000);
try
{
process2 = Process.GetProcessById(process.Id);
}
catch (ArgumentException)
{
break;
}
}
MessageBox.Show("done");
After Process.Start() check the process id of notepad.exe with the taskmanager and verify it is the same as process.Id;
Oh, and you really should use the full path to notepad.exe
var notepad = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.Windows), "notepad.exe");
Process.Start(notepad);
Upvotes: 1