{"id":27643,"date":"2007-03-13T10:00:00","date_gmt":"2007-03-13T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2007\/03\/13\/the-only-thing-you-can-do-with-display-names-is-display-them\/"},"modified":"2007-03-13T10:00:00","modified_gmt":"2007-03-13T10:00:00","slug":"the-only-thing-you-can-do-with-display-names-is-display-them","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20070313-00\/?p=27643","title":{"rendered":"The only thing you can do with display names is display them"},"content":{"rendered":"<p>\nThere are many functions that return strings called &#8220;display names&#8221;.\nAnd the only thing you can do with display names is display them.\nDon&#8217;t assume that the string actually means anything,\nbecause it doesn&#8217;t.\nTheoretically, a function like <code>SHGetFileInfo<\/code>\ncould be implemented as\n<\/p>\n<pre>\n...\n if (uFlags &amp; SHGFI_DISPLAYNAME) {\n  StringCchCopy(psfi-&gt;szDisplayName, MAX_PATH, TEXT(\"Booga!\"));\n }\n...\n<\/pre>\n<p>\nand your program should still work.\n<\/p>\n<p>\n(Of course, this is merely a ground rule.\nSpecific functions may have exceptions.\nFor example, the <code>IShellFolder::GetDisplayNameOf<\/code>\nhas a special flag <code>SHGDN_FORPARSING<\/code> flag which explicitly\nindicates that the string returned is designed to be parsed.)\n<\/p>\n<p>\nThe purpose of a &#8220;display name&#8221; is to be a string suitable for\ndisplaying to the user.\nThe display name for a file, for example, might be the file name,\nor it might have the extension removed, or the name might even\nbe translated into the user&#8217;s preferred language!\nFor example, on an English system with the German multilanguage\npack installed and active, asking for the display name of\n<code>C:\\Documents and Settings\\Raymond\\My Documents<\/code>\nwill return <code>Eigene Dateien<\/code> because that&#8217;s the\nname for My Documents in German.\n<\/p>\n<p>\nIf your program assumed that the display name of\n<code>C:\\Documents and Settings\\Raymond\\My Documents<\/code>\nwould be something like &#8220;My Documents&#8221;,\nyour program is in for a big surprise when I run it.\n<\/p>\n<p>\nOne of my colleagues was investigating a bug reported against\na program that wouldn&#8217;t run.\nIt claimed that the CD-ROM was not in the drive,\neven though it was.\nWhy can&#8217;t the program find its CD-ROM?\n<\/p>\n<p>\nAfter a few days&#8217; investigation, my colleague found the reason.\nThe program wanted to find its CD-ROM,\nso it walked through\nall 26 drive letters and called\n<code>SHGetFileInfo<\/code> passing the <code>SHGFI_DISPLAYNAME<\/code> flag.\nSomething like this:\n<\/p>\n<pre>\n\/\/ The actual code was much, much more convoluted than this.\nchar LookForCD(LPCTSTR pszVolumeLabel)\n{\n for (TCHAR chDrive = TEXT('A'); chDrive &lt;= TEXT(&#039;Z&#039;); chDrive++) {\n  TCHAR szRoot[4];\n  wsprintf(szRoot, TEXT(&quot;%c:\\\\&quot;), chDrive);\n  SHFILEINFO sfi;\n  if (SHGetFileInfo(szRoot, 0, &amp;sfi, sizeof(sfi), SHGFI_DISPLAYNAME)) {\n   TCHAR szExpected[MAX_PATH];\n   wsprintf(szExpected, TEXT(&quot;%s (%c:)&quot;), pszVolumeLabel, chDrive);\n   if (strcmp(szExpected, sfi.szDisplayName) == 0) {\n    return chDrive; \/\/ Found it!\n   }\n  }\n }\n return 0; \/\/ not found\n}\n<\/pre>\n<p>\nThe program asked for the display name of each drive and\nlooked for one whose display name was of the form\n<code>LABEL&nbsp;(D:)<\/code>,\nwhere <code>LABEL<\/code> is the volume label they&#8217;re looking for\nand <code>D:<\/code> is the drive letter.\n<\/p>\n<p>\nIn othe words, they were trying to interpret the display name.\n<\/p>\n<p>\nDon&#8217;t do that.\nThere is no guarantee that the display name for a CD-ROM\nwill be of any particular form.\nThe default in Windows&nbsp;XP happens to be <code>LABEL&nbsp;(D:)<\/code>,\nbut there\nare a variety of system policies\nthat can be used to change this,\nand if any of those policies is in effect, the program can&#8217;t find\nits CD-ROM and refuses to run.\n<\/p>\n<p>\n(For the record, the correct way of doing this would be to pass\neach drive letter to the\n<code>GetDriveType<\/code> function to see if it is a\n<code>DRIVE_CDROM<\/code>;\nfor each such drive,\ncall <code>GetVolumeInformation<\/code>\nto get the CD-ROM&#8217;s volume label.)\n<\/p>\n<p>\nSo remember,\ndisplay names are just for display purposes.&dagger;\n<\/p>\n<p>\n<b>Nitpicker&#8217;s corner<\/b>\n<\/p>\n<p>\n&dagger;See parenthetical remark at the top of this entry for clarification.\nThe sentence intentionally overlooked the exceptions in order to provide\na punchier ending to the story.\nIt&#8217;s called <i>writing style<\/i> and is a valid literary technique.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are many functions that return strings called &#8220;display names&#8221;. And the only thing you can do with display names is display them. Don&#8217;t assume that the string actually means anything, because it doesn&#8217;t. Theoretically, a function like SHGetFileInfo could be implemented as &#8230; if (uFlags &amp; SHGFI_DISPLAYNAME) { StringCchCopy(psfi-&gt;szDisplayName, MAX_PATH, TEXT(&#8220;Booga!&#8221;)); } &#8230; and [&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-27643","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There are many functions that return strings called &#8220;display names&#8221;. And the only thing you can do with display names is display them. Don&#8217;t assume that the string actually means anything, because it doesn&#8217;t. Theoretically, a function like SHGetFileInfo could be implemented as &#8230; if (uFlags &amp; SHGFI_DISPLAYNAME) { StringCchCopy(psfi-&gt;szDisplayName, MAX_PATH, TEXT(&#8220;Booga!&#8221;)); } &#8230; and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27643","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=27643"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/27643\/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=27643"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=27643"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=27643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}