{"id":91401,"date":"2015-10-09T07:00:00","date_gmt":"2015-10-09T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151009-00\/?p=91401\/"},"modified":"2019-03-13T12:20:27","modified_gmt":"2019-03-13T19:20:27","slug":"20151009-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20151009-00\/?p=91401","title":{"rendered":"How does a shell namespace extension provide icons for virtual items that track the standard icons set by the user&#8217;s file associations?"},"content":{"rendered":"<p>A customer asked, &#8220;What is the correct way to retrieve the icon associated with a file extension? We are writing a shell namespace extension that holds virtual file content, and we want to show the icon that would have been shown if the file were a physical file on disk rather than a virtual one. We tried using <code>SH&shy;Get&shy;File&shy;Info<\/code>, expecting it to return the icon location and index, but the <code>szDisplay&shy;Name<\/code> comes out as a blank string. (See sample program attached.) What&#8217;s the right way to get the location so we can return it in our own <code>Get&shy;UI&shy;Object&shy;Of(IExtract&shy;Icon)<\/code> handler?&#8221; <\/p>\n<pre>\n#include &lt;windows.h&gt;\n#include &lt;iostream&gt;\n\nint main()\n{\n SHFILEINFOW info;\n ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\n ::SHGetFileInfoW(L\".txt\", FILE_ATTRIBUTE_NORMAL,\n    &amp;info, sizeof(info),\n    SHGFI_ICONLOCATION | <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/06\/01\/145428.aspx\">SHGFI_USEFILEATTRIBUTES<\/a>);\n std::wcout &lt;&lt; info.szDisplayName &lt;&lt; std::endl;\n std::wcout &lt;&lt; info.iIcon &lt;&lt; std::endl;\n return 0;\n}\n<\/pre>\n<p>The location is coming out blank because the file location returned is <code>GIL_NOT&shy;FILENAME<\/code> so there is no file name to return. <\/p>\n<p>But let&#8217;s look past the question to the problem. The problem is that you want to implement <code>IShell&shy;Folder::Get&shy;UI&shy;Object&shy;Of(IExtract&shy;Icon)<\/code> for your shell namespace extension. Your plan is to create a custom implementation of <code>IExtract&shy;Icon<\/code> and tell it to report the information you obtained from <code>SH&shy;Get&shy;File&shy;Info<\/code>. The catch is that this information is lossy because <code>IExtract&shy;Icon::Get&shy;Icon&shy;Location<\/code> returns additional information that is not captured by <code>SH&shy;Get&shy;File&shy;Info<\/code>. <\/p>\n<p>Avoid the loss of fidelity by removing the middle man. Just ask for the standard icon extractor and return <i>that<\/i>. <\/p>\n<p>We start with a helper function that takes its inspiration from <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/09\/20\/231739.aspx\"><code>Get&shy;UI&shy;Object&shy;Of&shy;File<\/code><\/a> but applies a little seasoning from <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/05\/03\/10415778.aspx\"><code>Create&shy;Simple&shy;Pidl<\/code><\/a>: <\/p>\n<pre>\nHRESULT GetUIObjectOfVirtualFile(HWND hwnd, LPCWSTR pszPath,\n    REFIID riid, void **ppv)\n{\n  *ppv = nullptr;\n\n  WIN32_FIND_DATAW fd = {};\n  fd.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;\n  CComHeapPtr&lt;ITEMIDLIST_ABSOLUTE&gt; spidlSimple;\n  HRESULT hr = CreateSimplePidl(&amp;fd, pszPath, &amp;spidlSimple);\n  if (FAILED(hr)) return hr;\n\n  CComPtr&lt;IShellFolder&gt; spsf;\n  PCUITEMID_CHILD pidlChild;\n  hr = SHBindToParent(spidlSimple, IID_PPV_ARGS(&amp;spsf), &amp;pidlChild);\n  if (FAILED(hr)) return hr;\n\n  return spsf-&gt;GetUIObjectOf(hwnd, 1, &amp;pidlChild, riid, NULL, ppv);\n}\n<\/pre>\n<p>This helper function is like <code>Get&shy;UI&shy;Object&shy;Of&shy;File<\/code> except that it uses a simple pidl to get the UI object for a file that doesn&#8217;t actually exist. <\/p>\n<p>We can use this function to get the icon extractor for an arbitrary file extension. <\/p>\n<pre>\nHRESULT GetIconExtractorForExtension(\n    HWND hwnd,\n    PCWSTR pszExtension,\n    REFIID riid,\n    void **ppv)\n{\n *ppv = nullptr;\n\n wchar_t szPath[MAX_PATH];\n HRESULT hr = StringCchPrintfW(szPath, ARRAYSIZE(szPath),\n                              L\"C:\\\\a%ls\", pszExtension);\n if (FAILED(hr)) return hr;\n\n return GetUIObjectOfVirtualFile(hwnd, szPath, riid, ppv);\n}\n<\/pre>\n<p>and then use this function when handling the request for <code>IExtract&shy;Icon<\/code>. <\/p>\n<pre>\nif (interfaceId == IID_IExtractIconW ||\n    interfaceId == IID_IExtractIconA)\n{\n  return GetIconExtractorForExtension(hwnd, L\".txt\", riid, ppv);\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Forward to the standard implementation.<\/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-91401","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Forward to the standard implementation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91401","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=91401"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91401\/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=91401"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=91401"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=91401"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}