-->

start and close instance of explorer.exe

2019-07-30 18:19发布

问题:

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

回答1:

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?



回答2:

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