{"id":4073,"date":"2013-06-17T07:00:00","date_gmt":"2013-06-17T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/06\/17\/displaying-a-property-sheet-for-multiple-files\/"},"modified":"2013-06-17T07:00:00","modified_gmt":"2013-06-17T07:00:00","slug":"displaying-a-property-sheet-for-multiple-files","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130617-00\/?p=4073","title":{"rendered":"Displaying a property sheet for multiple files"},"content":{"rendered":"<p><P>\nToday&#8217;s Little Program will show a property sheet that covers multiple\nfiles,\njust like the one you get from Explorer if you multi-select a bunch\nof files and right-click them all then select <I>Properties<\/I>.\n<\/P>\n<P>\nIn fact, that description of how you do the operation interactively\nmaps directly to how you do the operation programmatically!\n<\/P>\n<PRE>\n#define UNICODE\n#define <A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/02\/12\/71851.aspx\">_UNICODE<\/A>\n#define <A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/01\/24\/10387757.aspx\">STRICT_TYPED_ITEMIDS<\/A>\n#include &lt;windows.h&gt;\n#include &lt;ole2.h&gt;\n#include &lt;shlobj.h&gt;\n#include &lt;atlbase.h&gt;\n#include &lt;atlalloc.h&gt;<\/p>\n<p>HRESULT GetUIObjectOf(\n    IShellFolder *psf,\n    HWND hwndOwner,\n    UINT cidl,\n    PCUITEMID_CHILD_ARRAY apidl, REFIID riid, void **ppv)\n{\n return psf-&gt;GetUIObjectOf(hwndOwner, cidl, apidl, riid, nullptr, ppv);\n}\n<\/PRE>\n<P>\nThe <CODE>Get&shy;UI&shy;Object&shy;Of<\/CODE> helper function\nmerely wraps the\n<CODE>IShell&shy;Folder::Get&shy;UI&shy;Object&shy;Of<\/CODE>\nmethod to insert the pesky <CODE>nullptr<\/CODE> parameter\nbetween the <CODE>riid<\/CODE> and <CODE>ppv<\/CODE>.\nThe <CODE>riid<\/CODE> and <CODE>ppv<\/CODE> parameters\nby convention go right next to each other,\nand the <CODE>IID_PPV_ARGS<\/CODE> macro assumes\nthat the function you&#8217;re calling follows that convention.\nUnfortunately, the people who designed\n<CODE>IShell&shy;Folder::Get&shy;UI&shy;Object&shy;Of<\/CODE>\ndidn&#8217;t get the memo, and we&#8217;ve been stuck with it ever since.\n<\/P>\n<PRE>\nHRESULT InvokeCommandByVerb(\n    IContextMenu *pcm,\n    HWND hwnd,\n    LPCSTR pszVerb)\n{\n HMENU hmenu = CreatePopupMenu();\n HRESULT hr = hmenu ? S_OK : E_OUTOFMEMORY;\n if (SUCCEEDED(hr)) {\n  hr = pcm-&gt;QueryContextMenu(hmenu, 0, 1, 0x7FFF, CMF_NORMAL);\n  if (SUCCEEDED(hr)) {\n   CMINVOKECOMMANDINFO info = { 0 };\n   info.cbSize = sizeof(info);\n   info.hwnd = hwnd;\n   info.lpVerb = pszVerb;\n   hr = pcm-&gt;InvokeCommand(&amp;info);\n  }\n  DestroyMenu(hmenu);\n }\n return hr;\n}\n<\/PRE>\n<P>\nThe <CODE>Invoke&shy;Command&shy;By&shy;Verb<\/CODE> function\nmerely\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/09\/20\/231739.aspx\">\nhosts an <CODE>IContext&shy;Menu<\/CODE> and invokes a single verb<\/A>.\n<\/P>\n<P>\nOkay, those are the only two helper functions we need this week.\nThe rest we can steal from earlier articles.\n<\/P>\n<P>\nFor the purpose of illustration,\nthe program will display a multi-file property sheet for the first\ntwo files in your\nMy Documents folder folder.\nRemember, Little Programs do little to no error checking.\n<\/P>\n<PRE>\nint __cdecl wmain(int, wchar_t **)\n{\n <A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/05\/20\/135841.aspx\">CCoInitialize<\/A> init;\n <A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2008\/05\/28\/8555658.aspx\">ProcessReference<\/A> ref;\n CComPtr&lt;IShellFolder&gt; spsf;\n <A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/08\/30\/10202076.aspx\">BindToCsidl<\/A>(CSIDL_MYDOCUMENTS, IID_PPV_ARGS(&amp;spsf));\n CComPtr&lt;IEnumIDList&gt; speidl;\n spsf-&gt;EnumObjects(nullptr, SHCONTF_NONFOLDERS, &amp;speidl);\n if (!speidl) return 0;\n CComHeapPtr&lt;ITEMID_CHILD&gt; spidl1;\n CComHeapPtr&lt;ITEMID_CHILD&gt; spidl2;\n if (speidl-&gt;Next(1, &amp;spidl1, nullptr) != S_OK) return 0;\n if (speidl-&gt;Next(1, &amp;spidl2, nullptr) != S_OK) return 0;\n PCUITEMID_CHILD rgpidl[2] = { spidl1, spidl2 };\n CComPtr&lt;IContextMenu&gt; spcm;\n GetUIObjectOf(spsf, nullptr, 2, rgpidl, IID_PPV_ARGS(&amp;spcm));\n if (!spcm) return 0;\n InvokeCommandByVerb(spcm, &#8220;properties&#8221;);\n return 0;\n}\n<\/PRE>\n<P>\nBecause everybody freaks out if I write code that doesn&#8217;t\nrun on Windows&nbsp;XP,\nI used the\n<CODE>Bind&shy;To&shy;CSIDL<\/CODE> function\ninstead of one of its more modern equivalents\nto get access to the My Documents folder.\n<\/P>\n<P>\nOnce we have My Documents,\nwe ask to enumerate its non-folders.\nIf the enumeration fails or says that there are no items (by returning\n<CODE>S_FALSE<\/CODE>), then we bail immediately.\n<\/P>\n<P>\nNext, we enumerate two items from the folder.\nIf we can&#8217;t get both, then we bail.\n<\/P>\n<P>\nWe then create a two-item array and\nget the <CODE>IContext&shy;Menu<\/CODE> UI object\nfor the collection.\n<\/P>\n<P>\nFinally, we invoke the <CODE>&#8220;properties&#8221;<\/CODE> verb on the context menu.\n<\/P>\n<P>\nAnd that&#8217;s it.\nIf you run this program, you&#8217;ll see a context menu for the first\ntwo files in your My Documents folder.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s Little Program will show a property sheet that covers multiple files, just like the one you get from Explorer if you multi-select a bunch of files and right-click them all then select Properties. In fact, that description of how you do the operation interactively maps directly to how you do the operation programmatically! #define [&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-4073","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today&#8217;s Little Program will show a property sheet that covers multiple files, just like the one you get from Explorer if you multi-select a bunch of files and right-click them all then select Properties. In fact, that description of how you do the operation interactively maps directly to how you do the operation programmatically! #define [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4073","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=4073"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4073\/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=4073"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4073"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4073"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}