{"id":11133,"date":"2011-03-25T07:00:00","date_gmt":"2011-03-25T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/03\/25\/how-do-i-monitor-or-even-control-the-lifetime-of-an-explorer-window\/"},"modified":"2011-03-25T07:00:00","modified_gmt":"2011-03-25T07:00:00","slug":"how-do-i-monitor-or-even-control-the-lifetime-of-an-explorer-window","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110325-00\/?p=11133","title":{"rendered":"How do I monitor, or even control, the lifetime of an Explorer window?"},"content":{"rendered":"<p>\nA customer wanted help with monitoring the lifetime of an\nExplorer window.\n<\/p>\n<blockquote CLASS=\"q\"><p>\nWe want to launch a copy of Explorer to open a specific folder,\nthen wait until the user closes the folder before continuing.\nWe tried launching a copy of Explorer with the folder on the\ncommand line, then doing a <code>Wait&shy;For&shy;Single&shy;Object<\/code>\non the process handle, but the wait sometimes completes immediately\nwithout waiting.\nHow do we wait until the user closes the Explorer window?\n<\/p><\/blockquote>\n<p>\nThis is another case of solving a problem halfway and then\nhaving trouble with the other half.\n<\/p>\n<p>\nThe reason that <code>Wait&shy;For&shy;Single&shy;Object<\/code>\nreturns immediately\nis that Explorer is a single-instance program (well, limited-instance).\nWhen you open an Explorer window, the request is handed off to\na running copy of Explorer, and the copy of Explorer you launched\nexits.\nThat&#8217;s why your <code>Wait&shy;For&shy;Single&shy;Object<\/code>\nreturns immediately.\n<\/p>\n<p>\nFortunately, the customer was willing to explain their underlying\nproblem.\n<\/p>\n<blockquote CLASS=\"q\"><p>\nWe have a wizard that creates some files in a directory\nbased on information provided by the user,\nand we want to launch Explorer to view that directory\nso users can verify that things\nare set up the way they want them.\nWhen users close the Explorer window, we ask them if everything\nwas good; if not, then we back up and let the user try again.\n<\/p><\/blockquote>\n<p>\nAha, the program is using Explorer as a &#8220;view this folder for\na little while&#8221; subroutine.\nUnfortunately, Explorer doesn&#8217;t work that way.\nFor example, the user might decide to use the Address Bar\nand go visit some other folders completely unrelated to your\nprogram, and your program would just be sitting there waiting\nfor the user to close that window;\nmeanwhile, the user doesn&#8217;t realize that your program is waiting\nfor it.\n<\/p>\n<p>\nWhat you can do is host the Explorer Browser control inside\na page of your wizard\nand control it with interfaces like\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms645992.aspx\">\n<code>IExplorer&shy;Browser<\/code><\/a>.\nYou can disable navigation in the Explorer Browser\n(so the user can look only at the folder\nyou want to preview),\nand the user can click <i>Back<\/i> if they want to try again\nor <i>Next<\/i> if they are happy and want to continue.\nThis has the additional advantage of keeping all the parts of\nyour wizard inside the wizard framework itself,\nallowing users to continue using the wizard navigation model\nthat they are already familiar with.\n<\/p>\n<p>\nA\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd940357.aspx\">\nsample program which uses the Explorer Browser control<\/a>\ncan be found in the Platform SDK.\n<\/p>\n<p>\nFor the impatient, here&#8217;s the\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/a> version.\nNote that this is the minimal version;\nin real life, you would probably want to set some options and stuff like that.\n<\/p>\n<pre>\n<font COLOR=\"blue\">#include &lt;shlobj.h&gt;\nIExplorerBrowser *g_peb;<\/font>\nvoid\nOnSize(HWND hwnd, UINT state, int cx, int cy)\n{\n<font COLOR=\"blue\">    if (g_peb) {\n        RECT rc = { 0, 0, cx, cy };\n        g_peb-&gt;SetRect(NULL, rc);\n    }<\/font>\n}\nBOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n<font COLOR=\"blue\">    BOOL fSuccess = FALSE;\n    RECT rc;\n    PIDLIST_ABSOLUTE pidl = NULL;\n    if (SUCCEEDED(CoCreateInstance(CLSID_ExplorerBrowser, NULL,\n                         CLSCTX_INPROC, IID_PPV_ARGS(&amp;g_peb))) &amp;&amp;\n        GetClientRect(hwnd, &amp;rc) &amp;&amp;\n        SUCCEEDED(g_peb-&gt;Initialize(hwnd, &amp;rc, NULL)) &amp;&amp;\n        SUCCEEDED(SHParseDisplayName(\n                         L\"C:\\\\Program Files\\\\Internet Explorer\",\n                                        NULL, &amp;pidl, 0, NULL)) &amp;&amp;\n        SUCCEEDED(g_peb-&gt;SetOptions(EBO_NAVIGATEONCE)) &amp;&amp;\n        SUCCEEDED(g_peb-&gt;BrowseToIDList(pidl, SBSP_ABSOLUTE))) {\n        fSuccess = TRUE;\n    }\n    ILFree(pidl);\n    return fSuccess;<\/font>\n}\nvoid\nOnDestroy(HWND hwnd)\n{\n    <font COLOR=\"blue\">if (g_peb) {\n        g_peb-&gt;Destroy();\n        g_peb-&gt;Release();\n    }<\/font>\n    PostQuitMessage(0);\n}\n<\/pre>\n<p>\nThis same technique of hosting the Explorer Browser control\ncan be used for other types of &#8220;build your own burrito&#8221; scenarios:\nFor example, you might\nhost the Explorer Browser control in a window and tell users\nto copy files into that window.\nWhen they click OK or Next or whatever, you can enumerate\nthe contents of the folder and do your business.\n<\/p>\n<p>\nArmed with this knowledge, you can answer these customers&#8217; questions:\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nWe have found that the process state of Explorer.exe changes to signaled\n<i>before<\/i> the process terminates.\nHere&#8217;s a sample program:\n<\/p>\n<pre>\nint _tmain(int argc, TCHAR **argv)\n{\n STARTUPINFO si = { sizeof(si) };\n PROCESS_INFORMATION pi;\n if (CreateProcess(TEXT(\"C:\\\\Windows\\\\Explorer.exe\"), TEXT(\" \/e,C:\\\\usr\"),\n                   NULL, NULL, FALSE, 0, NULL, NULL, &amp;si, &amp;pi)) {\n  WaitForSingleObject(pi.hProcess);\n  CloseHandle(pi.hProcess);\n  CloseHandle(pi.hThread);\n }\n return 0;\n}\n<\/pre>\n<p>\nIf we change &#8220;Explorer.exe&#8221; to &#8220;Notepad.exe&#8221; then the process handle\nis signaled after Notepad terminates, as expected.\n<\/p>\n<\/blockquote>\n<blockquote CLASS=\"q\"><p>\nWe have a 32-bit shell extension for which a 64-bit version is not\navailable.\nSince our clients are running 64-bit Windows,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/09\/29\/10069021.aspx\">\nthe 32-bit shell extension is not available in Explorer<\/a>.\nHow can we obtain access to this context menu?\n<\/p><\/blockquote>\n<blockquote CLASS=\"q\"><p>\nWe have a shell extension that is not UAC-compliant.\nIt requires that the user have administrative privileges in order\nto function properly.\nWe would rather not disable UAC across the board just for this\none shell extension.\nIs there a workaround that lets us run Explorer elevated temporarily?\n<\/p><\/blockquote>\n<p>\n<b>Bonus sample program<\/b>:\nThe\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd940358.aspx\">\nExplorer Browser Search Sample<\/a>\nshows how to filter the view.\n<\/p>\n<p>\n<b>Bonus alternative<\/b>:\nIf you really just want to watch Explorer windows rather than\nhost one,\nyou can use\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb757028.aspx\">\nthe ShellWindows object<\/a>,\nsomething I covered\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/07\/20\/188696.aspx\">\nmany years ago<\/a>\n(and followed up with a much shorter\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2005\/07\/05\/435657.aspx\">\nscripting version<\/a>).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&shy;For&shy;Single&shy;Object on the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-11133","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>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&shy;For&shy;Single&shy;Object on the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=11133"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11133\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=11133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=11133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=11133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}