{"id":92191,"date":"2015-11-30T07:00:00","date_gmt":"2015-11-30T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151130-00\/?p=92191\/"},"modified":"2019-03-13T12:22:22","modified_gmt":"2019-03-13T19:22:22","slug":"20151130-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20151130-00\/?p=92191","title":{"rendered":"Enumerating all the programs that can open a particular file extension"},"content":{"rendered":"<p>Today&#8217;s Little Program enumerates all the applications which are registered for a particular file extension and lets the user choose one. We then open a file with that chosen program. <\/p>\n<p>As always, Little Programs do little to no error checking. <\/p>\n<pre>\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;\n#include &lt;vector&gt;\n#include &lt;iostream&gt;\n\nstd::vector&lt;CComPtr&lt;IAssocHandler&gt;&gt; LoadHandlers(\n  PCWSTR extension,\n  ASSOC_FILTER filter)\n{\n  std::vector&lt;CComPtr&lt;IAssocHandler&gt;&gt; handlers;\n  CComPtr&lt;IEnumAssocHandlers&gt; enumerator;\n  SHAssocEnumHandlers(extension, filter, &amp;enumerator);\n  for (CComPtr&lt;IAssocHandler&gt; handler;\n       enumerator-&gt;Next(1, &amp;handler, nullptr) == S_OK;\n       handler.Release()) {\n       handlers.push_back(handler);\n  }\n  return handlers;\n}\n<\/pre>\n<p>The <code>Load&shy;Handlers<\/code> function shows off the meat of the program: We use <code>SHAssoc&shy;Enum&shy;Handlers<\/code> to enumerate all the handlers for a particular extension. The results get saved into a vector. <\/p>\n<pre>\nauto\nChooseHandler(\n  const std::vector&lt;CComPtr&lt;IAssocHandler&gt;&gt;&amp; handlers,\n  bool allowChooseMore) -&gt; decltype(handlers.size())\n{\n  decltype(handlers.size()) i;\n  for (i = 0; i &lt; handlers.size(); i++) {\n    CComHeapPtr&lt;wchar_t&gt; name;\n    handlers[i]-&gt;GetUIName(&amp;name);\n    std::wcout &lt;&lt; i &lt;&lt; L\": \" &lt;&lt; static_cast&lt;PCWSTR&gt;(name)\n                             &lt;&lt; std::endl;\n  }\n  if (allowChooseMore) {\n    std::wcout &lt;&lt; i &lt;&lt; L\": Show more handlers\" &lt;&lt; std::endl;\n    i++;\n  }\n\n  decltype(handlers.size()) selection;\n  std::wcin &gt;&gt; selection;\n  if (std::wcin.fail()) selection = i + 1;\n  return selection;\n}\n<\/pre>\n<p>The <code>Choose&shy;Handler<\/code> function prints the vector of handlers (and optionally adds a &#8220;Show more handlers&#8221; option). It collects the user&#8217;s reply and returns it, using <code>handlers.size()<\/code> to represent the &#8220;Show more handlers&#8221; option, if available. If the user&#8217;s input is invalid, we return a value that is out of range. (I&#8217;m assuming you don&#8217;t have four billion handlers.) <\/p>\n<pre>\nint __cdecl main(int, char**)\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\n  auto handlers = LoadHandlers(L\".txt\", ASSOC_FILTER_RECOMMENDED);\n  auto selection = ChooseHandler(handlers, true);\n  if (selection == handlers.size()) {\n    handlers = LoadHandlers(L\".txt\", ASSOC_FILTER_NONE);\n    selection = ChooseHandler(handlers, false);\n  }\n\n  if (selection &lt; handlers.size()) {\n    CComPtr&lt;IDataObject&gt; dobj;\n    <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/09\/20\/231739.aspx\">GetUIObjectOfFile<\/a>(nullptr, L\"C:\\\\windows\\\\win.ini\",\n                      IID_PPV_ARGS(&amp;dobj));\n    handlers[selection]-&gt;Invoke(dobj);\n  }\n  return 0;\n}\n<\/pre>\n<p>And here&#8217;s the main function that ties everything together. <\/p>\n<p>After some initial throat-clearing, it loads up the recommended handlers for the <code>.txt<\/code> file extension and lets the user choose from among them. <\/p>\n<p>If the user says &#8220;Show more handlers&#8221;, then we load up all handlers and try again. <\/p>\n<p>We then take the user&#8217;s selection and open <code>WIN.INI<\/code> with that program. <\/p>\n<p><b>Exercise<\/b>: What is the purpose of the <code>Process&shy;Reference<\/code> object? <\/p>\n","protected":false},"excerpt":{"rendered":"<p>SHAssocEnumHandlers.<\/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-92191","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>SHAssocEnumHandlers.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/92191","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=92191"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/92191\/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=92191"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=92191"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=92191"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}