How do I monitor, or even control, the lifetime of an Explorer window?

A customer wanted help with monitoring the lifetime of an Explorer window.

We want to launch a copy of Explorer to open a specific folder, then wait until the user closes the folder before continuing. We tried launching a copy of Explorer with the folder on the command line, then doing a Wait­For­Single­Object on the process handle, but the wait sometimes completes immediately without waiting. How do we wait until the user closes the Explorer window?

This is another case of solving a problem halfway and then having trouble with the other half.

The reason that Wait­For­Single­Object returns immediately is that Explorer is a single-instance program (well, limited-instance). When you open an Explorer window, the request is handed off to a running copy of Explorer, and the copy of Explorer you launched exits. That's why your Wait­For­Single­Object returns immediately.

Fortunately, the customer was willing to explain their underlying problem.

We have a wizard that creates some files in a directory based on information provided by the user, and we want to launch Explorer to view that directory so users can verify that things are set up the way they want them. When users close the Explorer window, we ask them if everything was good; if not, then we back up and let the user try again.

Aha, the program is using Explorer as a "view this folder for a little while" subroutine. Unfortunately, Explorer doesn't work that way. For example, the user might decide to use the Address Bar and go visit some other folders completely unrelated to your program, and your program would just be sitting there waiting for the user to close that window; meanwhile, the user doesn't realize that your program is waiting for it.

What you can do is host the Explorer Browser control inside a page of your wizard and control it with interfaces like IExplorer­Browser. You can disable navigation in the Explorer Browser (so the user can look only at the folder you want to preview), and the user can click Back if they want to try again or Next if they are happy and want to continue. This has the additional advantage of keeping all the parts of your wizard inside the wizard framework itself, allowing users to continue using the wizard navigation model that they are already familiar with.

A sample program which uses the Explorer Browser control can be found in the Platform SDK.

For the impatient, here's the scratch program version. Note that this is the minimal version; in real life, you would probably want to set some options and stuff like that.

#include <shlobj.h>

IExplorerBrowser *g_peb;

OnSize(HWND hwnd, UINT state, int cx, int cy)
    if (g_peb) {
        RECT rc = { 0, 0, cx, cy };
        g_peb->SetRect(NULL, rc);

OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    BOOL fSuccess = FALSE;
    RECT rc;
    if (SUCCEEDED(CoCreateInstance(CLSID_ExplorerBrowser, NULL,
                         CLSCTX_INPROC, IID_PPV_ARGS(&g_peb))) &&
        GetClientRect(hwnd, &rc) &&
        SUCCEEDED(g_peb->Initialize(hwnd, &rc, NULL)) &&
                         L"C:\\Program Files\\Internet Explorer",
                                        NULL, &pidl, 0, NULL)) &&
        SUCCEEDED(g_peb->SetOptions(EBO_NAVIGATEONCE)) &&
        SUCCEEDED(g_peb->BrowseToIDList(pidl, SBSP_ABSOLUTE))) {
        fSuccess = TRUE;
    return fSuccess;

OnDestroy(HWND hwnd)
    if (g_peb) {

This same technique of hosting the Explorer Browser control can be used for other types of "build your own burrito" scenarios: For example, you might host the Explorer Browser control in a window and tell users to copy files into that window. When they click OK or Next or whatever, you can enumerate the contents of the folder and do your business.

Armed with this knowledge, you can answer these customers' questions:

We have found that the process state of Explorer.exe changes to signaled before the process terminates. Here's a sample program:

int _tmain(int argc, TCHAR **argv)
 STARTUPINFO si = { sizeof(si) };
 if (CreateProcess(TEXT("C:\\Windows\\Explorer.exe"), TEXT(" /e,C:\\usr"),
                   NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
 return 0;

If we change "Explorer.exe" to "Notepad.exe" then the process handle is signaled after Notepad terminates, as expected.

We have a 32-bit shell extension for which a 64-bit version is not available. Since our clients are running 64-bit Windows, the 32-bit shell extension is not available in Explorer. How can we obtain access to this context menu?

We have a shell extension that is not UAC-compliant. It requires that the user have administrative privileges in order to function properly. We would rather not disable UAC across the board just for this one shell extension. Is there a workaround that lets us run Explorer elevated temporarily?

Bonus sample program: The Explorer Browser Search Sample shows how to filter the view.

Bonus alternative: If you really just want to watch Explorer windows rather than host one, you can use the ShellWindows object, something I covered many years ago (and followed up with a much shorter scripting version).

Comments (19)
  1. Sunil Joshi says:

    Query 1:

    The handle is being signalled after the launched process terminates. But the process they launched just handed over control to an existing explorer process, which hasn't terminated.

    Query 2:

    Host an explorer browser control in a 32-bit process in which the shell extension is loaded.

    Query 3:

    Host an explorer browswer control in an elevated process in which the shell extension is loaded.

  2. Henke37 says:

    I smell a trap at the end. The shell is not limited to explorer.exe, it can be nearly any program on the computer that is using it. As such, a shell extension does not just need explorer.exe elevanted, but every possible application that loads the shell extension (lets assume it can be loaded by all shell users). The consequences are way too big to justify running the shell extension elevated, because it would mean that (nearly) everything is elevated.

    And that is before we discuss the fact that when explorer.exe starts stuff said stuff will inherit the elevation.

  3. Alex Grigoriev says:

    "We have a wizard that creates some files in a directory based on information provided by the user, and we want to launch Explorer to view that directory so users can verify that things are set up the way they want them. When users close the Explorer window, we ask them if everything was good;"

    Marketing asks the programmers do the darndest and stupidest things… News at 11.


    Q1: A program that calls CreateProcess doesn't have a clue about what the target process does. The handle state only reflects the target process state, nothing more.

  4. Bob says:

    Funny that this sample program with c:\Program Files  hard-coded comes so soon after a posting on SHGetFolderPath.  I know…just a stripped down sample program to demonstrate the concepts…but it shows how seductive it can be to do things the easy way.

  5. Sunil Joshi says:

    @Alex Grigoriev

    I know that – the problem in customer query 1 is just another example of the original problem that Mr Chen handles at the top of the article.

  6. Dan Bugglin says:

    @sunil Neither 2 or 3 indicate they want to host an explorer window.  The whole point of a shell extension is that it is available in ANY explorer window… otherwise it's fairly useless and you might as well just have the functionality incorporated in the program you were going to host the Explorer window in.

    Plus, you can only host Explorer windows starting with Vista, and plenty of people still use XP.

    My answers:

    1) Explorer can only run as a single instance except in a very specific circumstance, so other instances will signal the main process and immediately exit.

    2) Build a 64-bit version of your shell extension for 64-bit systems if you have the source, or install the 32-bit version of your OS.

    3) This is a bad idea, since if you succeed all processes run afterwards will be elevated, so you have in effect disabled UAC anyway.  Instead, change necessary folder/registry key permissions so the extension can run under a normal user account.  Though it would be best just to fix the extension if possible.

  7. Adam Rosenfield says:

    This is unrelated to customer #1's problem (others have already pointed out the problem), but this command line:

    CreateProcess(TEXT("C:\Windows\Explorer.exe"), TEXT(" /e,C:\usr"), …)

    Will start up Explorer with argv[0] as "/e,C:\usr" instead of argv[1] as that, which will fail to set the starting directory of the new window.

  8. Sunil Joshi says:

    @The MAZZTer

    I think in Q2 and Q3 it's strongly implied that the extensions are 3rd party and that the sources aren't to hand. Clearly they need some functionality in the extension which they can't otherwise reproduce.

  9. Adam Rosenfield says:

    Actually I take that back, it will start Explorer with argv[0] as the empty string, which is probably ok (most programs ignore argv[0]; sometimes they print it out with error messages, but even that is harmless).  I didn't notice the leading space, which I presume is meaningful to CommandLineToArgvW.

  10. Paul says:


    I think you will find the use of hard coded paths isn't a case of doing things the "easy way" but actually results in an example free from code noise that isn't relevant to the point.

  11. jmthomas says:

    Would substituting something like "common open" avoid the customer's problem, or is it tied too much to explorer?

  12. Chen #2 says:

    I think I will start to blog and let my readers solve my customer's problem.

  13. Fred says:

    I think if you use the program group (program manager) api's you can get explorer to do this for you.

  14. Evan says:

    My immediate thought (besides "that's maybe not a wonderful thing to want to do") was that explorer takes a /separate flag that tells it to start a new process. (I've used that to make explorer windows with 'runas'.) I wonder if that would work.


    And why does using hard-coded paths result in an example "free from code noise"? Because it's easier and more direct than doing it right.

  15. Joshua says:

    Just saw a file in Windows XP Explorer modified "Tomorrow". Amusing.

  16. pete.d says:

    See also the Windows API Code Pack, which provides (among other things) a convenient managed code (.NET) library supporting the ExplorerBrowser control.

  17. Troll says:

    The way the shell team has handled 32-bit shell extensions in 64-bit Windows is the most wrongest and worst possible way for users who want to migrate to 64-bit Windows. They even killed off the ability to run 32-bit Explorer in 64-bit Windows 7. Ultimately, users suffer because MS didn't bother to create a bridge for 32-bit shell extensions in 64-bit Explorer. I recently found a little tool ( that lets you access 32-bit context menu and property sheet handlers at least in 64-bit Explorer. Something like this should be built-in into WIndows. Windows 8 maybe. Shell team, take a look at that tool and ease people's lives.

    MS even screwed up with their own Windows Live Essentials which wrongly install 32-bit AutoPlay handlers on 64-bit Windows. See…/The-case-of-the-missing-AutoPlay-handler.aspx

  18. Paul says:


    I guess I was just annoyed at this cropping up again, nearly every single post Raymond does that includes a hard coded path gets a comment like that. The main part of the example in this article is about 11 lines, if wrapping is ignored) – would it really be improved by adding another 10 lines or so of code that is dealing with simply returning a path?

  19. Chris J says:

    @Chen #2 … it already exists: it's called Stackoverflow :-)

Comments are closed.