15

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:

  • Reinstalled .NET.
  • Closed any processes I don't know in task manager.
  • Windows has not yet been activated on this machine.
  • Following advice in the comments, I tried getting the 'existing' process Id using 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.
  • On the problem machine, the resulting notepad process's ParentID is the ID of the notepad process the code manually starts, or in other words, notepad is spawning a child process and terminating itself.
Community
  • 1
  • 1
Rotem
  • 21,452
  • 6
  • 62
  • 109
  • 1
    Is it possible that there was another Notepad opened before? So you create one, kill one, but still see the old Notepad? `proc.WaitForExit()` may return immediately, if the process couldn't be created or was terminated straightaway due to some reasons, for example lack of privileges of the original code to create new processes. – oleksii Jan 17 '12 at 13:05
  • @oleskii, no I have made sure of this. Notepad is only being used here as a process "that everyone knows", this problem occurs no matter which file is used for the process. – Rotem Jan 17 '12 at 13:07
  • @oleskii "proc.WaitForExit() may return immediately, if the process couldn't be created or was terminated straightaway due to some reasons" - wouldn't the process also actually be terminated in this case? – Rotem Jan 17 '12 at 13:10
  • 3
    I'm not aware of different comportments for `WaitForExit()`. Are you sure the process you start is the same as the process you see opened in taskmgr? Could you check the PID (process ID) of your opened Notepad.exe instance is the same as the PID of your `proc` instance? – ken2k Jan 17 '12 at 13:10
  • @Rotem "wouldn't the process also actually be terminated in this case" yes it will be terminated (not seen in Task Manager). As ken2k says try checking the PID. – oleksii Jan 17 '12 at 13:13
  • Totally grabbing at straws, but could the security context have anything to do with it, by that I mean the priviledges of the account under which the process runs? No reason to think that would be it, just trying to think what might be different in that particular environment. – Myles McDonnell Jan 17 '12 at 13:15
  • @oleskii / kenk2k : Well it seems you guys are both right! On the 'problem machine', the PID of the process returned from `GetProcessesByName(notepad)` is different than that of process I am spawning. This is interesting, yet brings me no closer to a reason or a solution. Why could this be happening, and why only on this machine? – Rotem Jan 17 '12 at 13:17
  • @Myles : I grabbed at the same straw :) I tried running as administrator, same result. – Rotem Jan 17 '12 at 13:19
  • 6
    Drag the machine to the 4th floor, open the window and let it slip. This isn't worth your time. – Hans Passant Jan 17 '12 at 13:22
  • Hum... Could you check what is the parent process of your opened notepad.exe instance? See here for a how to: http://blogs.msdn.com/b/toffer/archive/2005/07/21/441540.aspx – ken2k Jan 17 '12 at 13:25
  • @oleskii / kenk2k : Sorry! I spoke too soon, what I wrote in the previous comment was a mistake. There is actually no process being returned by `GetProcessesByName(notepad)` on the problem machine, though the process does exist in the task manager, and more visibly, on the screen. – Rotem Jan 17 '12 at 13:25
  • @Hans lol, unfortunately it's halfway around the world, I'm troubleshooting it remotely. – Rotem Jan 17 '12 at 13:26
  • @Rotem Then maybe it's a malware that hides itself as notepad.exe ;) More seriously, I'm curious to know the parent process of your opened notepad instance. – ken2k Jan 17 '12 at 13:27
  • I wonder if this has something to do with you trouble shooting it remotely? By what means are you connected? It sounds as if something is intercepting the call to the OS to start notepad and starting notepad in another process, which may be something to do with terminal server? Again, straw grabbing. – Myles McDonnell Jan 17 '12 at 13:31
  • @Myles - currently using Teamviewer, but the problem also occurs locally, that's why I was called. Moreover, the problem doesn't occur when connected by the same means to other machines. ken2k - working on it... – Rotem Jan 17 '12 at 13:35
  • hhmmm, it's almost certainly environmental. I would be looking for differences in the build of the machine, what does it have installed that the others don't or what may have been configured differently? Don't forget to post the answer when you get it, I'm very curious to know what it is now! :) – Myles McDonnell Jan 17 '12 at 13:42
  • @Myles The only thing I can see right off is that windows activation period has passed on the machine, though I would be amazed to discover that is the reason. – Rotem Jan 17 '12 at 13:50
  • Could there be some malevolent software involved? – Myles McDonnell Jan 17 '12 at 13:59
  • @Myles I Tried closing all the processes I didn't know in the task manager. I'll update if I find any new information. – Rotem Jan 17 '12 at 14:10
  • @kenk2k : Seems there is no way for me to get the 'existing' process, I tried the method from the link you posted but it couldn't find it either. – Rotem Jan 17 '12 at 14:11
  • I'm sorry, I've checked the link I provided to you, and it looks bad to me. Wait a few minutes, I'll give you something better. – ken2k Jan 17 '12 at 14:47
  • Please try this: http://pastebin.com/Yg5HEabY – ken2k Jan 17 '12 at 14:55
  • @Rotem is this a x64 bit machine? If you are looking for the process by name you may need to add *32 to the end of the process name. – Kev Ritchie Jan 17 '12 at 14:57
  • @ken2k Firstly thanks for going through all this trouble. The problem is not getting parent info from a process ID, the problem was getting the 'existing' process ID in the first place. However, I managed to do this by running the program twice. The first time I run it it opens notepad and then is not able to find it by name. When I run the program again it does find the previously opened notepad. What I've discovered is that the parent ID of the existing notepad is the ID of the notepad I am opening. I will update in the question. – Rotem Jan 17 '12 at 15:01
  • I wouldn't rely on a process name, especially when it's a multi-instance application such as notepad. The process ID should be always used to identify a process, not its name. – ken2k Jan 17 '12 at 15:01
  • @Kev Doing that doesn't find the process on any machine. ken2k: See update in question. – Rotem Jan 17 '12 at 15:09
  • 1
    Have you tried running it with `Process.StartInfo.UseShellExecute = false`? – Chris Shain Jan 17 '12 at 15:18
  • Would this be related to UAC? Do you get a prompt when notepad runs? It usually doesn't require elevation, but if elevation is needed it will kill the original process and relaunch it with different rights. – Joel Lucsy Jan 17 '12 at 15:19
  • @Chris Bingo! That did it. Please post it as an answer, and if you could also try to explain why it is the cause and why only on this machine. Thanks! – Rotem Jan 17 '12 at 15:21
  • Ok! So based on your edit, notepad.exe spawns a new instance of himslef and then terminates, which explains why your WaitForExit doesn't block your code. Now the question is: why does notepad behaves in such a strange way? I would recommend launching an anti-virus scan. Maybe some malware modified the notepad.exe process. – ken2k Jan 17 '12 at 15:21
  • @Joel - UAC was disabled – Rotem Jan 17 '12 at 15:21
  • @Ken - it happens with every process, not just notepad. Chris's comment seems to be right on the mark. – Rotem Jan 17 '12 at 15:22
  • Yes, I've seen the answer of Chris after I posted my comment^^ good to see someone finally found the answer :-p – ken2k Jan 17 '12 at 15:24
  • @ken2k In any case thanks so much for working vigorously on the problem. – Rotem Jan 17 '12 at 15:37

2 Answers2

7

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.

Community
  • 1
  • 1
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • Thanks! While your solution solves my problem, I would love to find the reason why it only seemed to have an effect on just one machine out of a group of about 50. – Rotem Jan 17 '12 at 15:44
  • I am hoping @EricLippert gets in here and fields the "Why this happens" part. I'm not that sharp. – Chris Shain Jan 17 '12 at 15:47
  • 2
    I haven't the faintest idea. I'm an expert on the design and implementation of the C# language and its compiler. I know practically nothing about how Windows manages processes. – Eric Lippert Jan 17 '12 at 16:21
1

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);
Jürgen Steinblock
  • 30,746
  • 24
  • 119
  • 189