{"id":110547,"date":"2024-11-20T07:00:00","date_gmt":"2024-11-20T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110547"},"modified":"2024-11-20T07:59:00","modified_gmt":"2024-11-20T15:59:00","slug":"20241120-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241120-00\/?p=110547","title":{"rendered":"How do I determine whether Explorer is showing or hiding file extensions?"},"content":{"rendered":"<p>Say you want to determine in your program whether Explorer is showing or hiding file extensions.<\/p>\n<p>You can do this by calling <code>SHGetSettings<\/code>:<\/p>\n<pre>bool AreExtensionsShown()\r\n{\r\n    SHELLFLAGSTATE sfs;\r\n    SHGetSettings(&amp;sfs, SSF_SHOWEXTENSIONS);\r\n    return sfs.fShowExtensions;\r\n}\r\n<\/pre>\n<p>But this is answering the question without understanding the problem.<\/p>\n<p>Even if Explorer is showing extensions, that doesn&#8217;t mean that <i>all<\/i> extensions are shown. Some extensions are <i>never<\/i> shown, like <tt>.lnk<\/tt>. Some extensions are <i>always<\/i> shown, like <tt>.dll<\/tt>. And some rules are contextual: For example, if a file name consists only of the extension, then the extension is always shown.<\/p>\n<p>So maybe what we have is an <a href=\"https:\/\/en.wikipedia.org\/wiki\/XY_problem\"> XY problem<\/a>. &#8220;I have the name of a file and I want to display it in the same way that Explorer does. In order to do that, I need to know whether Explorer is showing extensions, so I will ask how to query that setting.&#8221;<\/p>\n<p>But querying the setting doesn&#8217;t tell you everything you need to know in order to format a file name for display in the same way that Explorer does. To take all the display rules into account, you can ask <code>SHGetFileInfo<\/code> to produce the name that Explorer would show if it encountered a file with a specific name.<\/p>\n<pre>SHFILEINFO sfi;\r\nif (SHGetFileInfo(L\"something.txt\", FILE_ATTRIBUTE_NORMAL,\r\n    &amp;sfi, sizeof(sfi),\r\n    SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME)) {\r\n    \/\/ use the name in sfi.szDisplayName\r\n}\r\n<\/pre>\n<p>Note that the file attributes should be <code>FILE_<wbr \/>ATTRIBUTE_<wbr \/>NORMAL<\/code> if you want to display the name for a hypothetical file named <tt>something.txt<\/tt>, or <code>FILE_<wbr \/>ATTRIBUTE_<wbr \/>DIRECTORY<\/code> if you want to display the name for a hypothetical directory named <tt>something.txt<\/tt>.<\/p>\n<p>But wait, this still might be an XY problem. &#8220;I got the name of a file from the system, and I want to display it the same way that Explorer does. So I&#8217;ll ask how to obtain the name that Explorer would show when faced with a file with a specific name.&#8221; But that&#8217;s still not enough, because the name that Explorer displays for a file depends on more than just the file&#8217;s name.<\/p>\n<p>For example, the file named <tt>C:\\<wbr \/>ProgramData\\<wbr \/>Microsoft\\<wbr \/>Windows\\<wbr \/>Start Menu\\<wbr \/>Programs\\<wbr \/>System Tools\\<wbr \/>Task Manager.lnk<\/tt> displays as <i>Aktivitets\u00adhanteraren<\/i> on Swedish systems. To get this name, you need to provide a full path to <code>SHGetFileInfo<\/code> and say that it should consult the actual file (by removing the <code>SHGFI_<wbr \/>USE\u00adFILE\u00adATTRIBUTES<\/code> flag).<\/p>\n<pre>SHFILEINFO sfi;\r\nif (SHGetFileInfo(L\"C:\\\\ProgramData\\\\Microsoft\\\\\"\r\n                  L\"Windows\\\\Start Menu\\\\Programs\\\\\"\r\n                  L\"System Tools\\\\Task Manager.lnk\",\r\n                  0,\r\n                  &amp;sfi, sizeof(sfi),\r\n                  SHGFI_DISPLAYNAME)) {\r\n    \/\/ use the name in sfi.szDisplayName\r\n}\r\n<\/pre>\n<p>If you received the file in the form of a pidl or <code>IShellItem<\/code>, you can take advantage of the information already cached in the pidl \/ <code>IShellItem<\/code> and obtain the display name without further disk access.<\/p>\n<pre>\/\/ If you have an IShellFolder + child pidl\r\nIShellFolder* psf = \u27e6 ... \u27e7;\r\nPIDLIST_CHILD pidl = \u27e6 ... \u27e7;\r\nSTRRET str;\r\n\r\nif (SUCCEEDED(psf-&gt;GetDisplayNameOf(pidl,\r\n                 SHGDN_NORMAL, &amp;str))) {\r\n    wil::unique_cotaskmem_string name;\r\n    if (SUCCEEDED(StrRetToStrW(&amp;str, pidl, name.put())) {\r\n        \/\/ use the name in \"name\"\r\n    }\r\n}\r\n\r\n\/\/ If you have an absolute pidl\r\nPIDLIST_ABSOLUTE pidlAbsolute = \u27e6 ... \u27e7;\r\nSHFILEINFO sfi;\r\nif (SHGetFileInfo((PCWSTR)pidlAbsolute,\r\n                  0,\r\n                  &amp;sfi, sizeof(sfi),\r\n                  SHGFI_PIDL | SHGFI_DISPLAYNAME)) {\r\n    \/\/ use the name in sfi.szDisplayName\r\n}\r\n\r\n\/\/ If you have an IShellItem\r\nIShellItem* psi = \u27e6 ... \u27e7;\r\nwil::unique_cotaskmem_string name;\r\nif (SUCCEEDED(psi_&gt;GetDisplayName(SIGDN_NORMALDISPLAY,\r\n                    name.put()))) {\r\n    \/\/ use the name in \"name\"\r\n}\r\n<\/pre>\n<p>If your real question is &#8220;How can I display this thing the same way that Explorer does?&#8221; then ask that question. Don&#8217;t ask, &#8220;How can I determine whether Explorer is showing or hiding file extensions?&#8221; and try to replicate Explorer&#8217;s name-generation algorithm from that one Boolean value.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can ask, but maybe you&#8217;re asking the wrong question.<\/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-110547","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You can ask, but maybe you&#8217;re asking the wrong question.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110547","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=110547"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110547\/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=110547"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110547"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110547"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}