{"id":9363,"date":"2011-10-17T07:00:00","date_gmt":"2011-10-17T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/10\/17\/why-is-there-a-csidl_desktop-value-if-you-need-the-desktop-in-order-to-get-it-anyway\/"},"modified":"2011-10-17T07:00:00","modified_gmt":"2011-10-17T07:00:00","slug":"why-is-there-a-csidl_desktop-value-if-you-need-the-desktop-in-order-to-get-it-anyway","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20111017-00\/?p=9363","title":{"rendered":"Why is there a CSIDL_DESKTOP value if you need the desktop in order to get it anyway?"},"content":{"rendered":"<p>\nJohn asks\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/07\/30\/9852685.aspx#9853402\">\nwhy there is a special constant <code>CSIDL_DESKTOP<\/code>\ndefined for the desktop<\/a>.\nAfter all, in order to use <code>CSIDL_DESKTOP<\/code>,\nyou need to call <code>SHGet&shy;Desktop&shy;Folder<\/code> and then\nbind to it.\nWhat&#8217;s the point of having an <code>ITEM&shy;ID&shy;LIST<\/code> that\nrepresents the desktop if, in order to use it,\nyou first need to get the desktop?\n<\/p>\n<p>\nIt&#8217;s like asking why the file system uses\n<code>.<\/code> (dot)\nto refer to the current directory.\nYou&#8217;re already <i>in<\/i> the current directory.\nIn order to resolve <code>.<\/code> (dot), you already need to have\nthe current directory, so why bother with the dot at all?\n<\/p>\n<p>\nBecause it is often convenient to give a name to your starting point.\n<\/p>\n<p>\nSuppose somebody wants to save a file to the desktop.\nHow would you represent this as an <code>ITEM&shy;ID&shy;LIST<\/code>?\nIf the only thing you can do is fill in the blank in the\nsentence,\n&#8220;Start with the desktop folder, then go to ________, then\nsave the file there,&#8221;\nthen you need a way to say &#8220;where you are now.&#8221;\n<\/p>\n<p>\nAnd that&#8217;s what <code>CSIDL_DESKTOP<\/code> gives you.\nAn <code>ITEM&shy;ID&shy;LIST<\/code> that says &#8220;Where you are now.&#8221;\n<\/p>\n<p>\nBesides, if <code>CSIDL_DESKTOP<\/code> weren&#8217;t defined,\nsomebody would have invented it.\nSay your program has a list of directories it wants to operate on,\nsay, the Documents folder, the Music folder,\nand the Shared Documents folder.\nGreat, so let me write a function:\n<\/p>\n<pre>\nvoid DoItIn(HWND hwnd, int csidl)\n{\n PIDLIST_ABSOLUTE pidl;\n if (SUCCEEDED(SHGetSpecialFolderLocation(\n                     hwnd, csidl, &amp;pidl))) {\n  IShellFolder *psf;\n  if (SUCCEEDED(SHBindToObject(NULL, pidl, NULL,\n                    IID_PPV_ARGS(&amp;psf)))) {\n   ...\n   psf-&gt;Release();\n  }\n  CoTaskMemFree(pidl);\n }\n}\nvoid DoItInStandardPlaces(HWND hwnd)\n{\n const static int csidls[] = {\n  CSIDL_MYDOCUMENTS,\n  CSIDL_MYMUSIC,\n  CSIDL_COMMON_DOCUMENTS,\n };\n for (int i = 0; i &lt; ARRAYSIZE(csidls); i++) {\n  DoItIn(hwnd, csidls[i]);\n }\n}\n<\/pre>\n<p>\nNow you want to add the desktop folder.\nOh wait, there is no <code>CSIDL<\/code> value for the desktop,\nso I&#8217;ll have to make one up.\n<\/p>\n<pre>\n\/\/ Our custom CSIDLs use the high word. None of the CSIDLs we use\n\/\/ set any bits in the high word, so we can use the high word to\n\/\/ detect whether we have a standard CSIDL or a custom CSIDL.\n#define CUSTOMCSIDL_DESKTOP 0x00010000\n#define ISCUSTOMCSIDL(csidl) HIWORD(csidl)\n#define STANDARDCSIDLOF(csidl) LOWORD(csidl)\nHRESULT MyGetSpecialFolderLocation(\n    HWND hwnd, int csidl, PIDLIST_ABSOLUTE *ppidl)\n{\n HRESULT hr;\n if (ISCUSTOMCSIDL(csidl)) {\n  *ppidl = (PIDLIST_ABSOLUTE)CoTaskMemAlloc(sizeof(WORD));\n  if (*ppidl) {\n   ppidl-&gt;mkid.cb = 0;\n   hr = S_OK;\n  } else {\n   hr = E_OUTOFMEMORY;\n  }\n } else {\n  hr = SHGetSpecialFolderLocation(hwnd, STANDARDCSIDLOF(csidl), ppidl);\n }\n return hr;\n}\n<\/pre>\n<p>\nOkay, cool, now I can add\n<\/p>\n<pre>\n const static int csidls[] = {\n  CSIDL_MYDOCUMENTS,\n  CSIDL_MYMUSIC,\n  CSIDL_COMMON_DOCUMENTS,\n  <font COLOR=\"blue\">CUSTOMCSIDL_DESKTOP,<\/font>\n };\n<\/pre>\n<p>\nOh wait, I also have to have a custom version of\n<code>SHBind&shy;To&shy;Object<\/code> that knows how to bind to\nthis special new type of pidl that means &#8220;where you are now.&#8221;\n<\/p>\n<pre>\nHRESULT MyBindToObject(IShellFolder *psf, PCUIDLIST_RELATIVE pidl,\n  IBindCtx *pbc, REFIID riid, void **ppv)\n{\n HRESULT hr;\n if (pidl-&gt;mkid.cb == 0) {\n  *ppv = NULL;\n  if (psf == NULL) {\n   hr = SHGetDesktopFolder(&amp;psf);\n   if (SUCCEEDED(hr)) {\n    hr = psf-&gt;QueryInterface(riid, ppv);\n    psf-&gt;Release();\n   }\n  } else {\n   hr = psf-&gt;QueryInterface(riid, ppv);\n  }\n } else {\n  hr = SHBindToObject(psf, pidl, pbc, riid, ppv);\n }\n return hr;\n}\n<\/pre>\n<p>\nCongratulations, you just reinvented <code>CSIDL_DESKTOP<\/code>.\n<\/p>\n<p>\nIt can be\n<a HREF=\"http:\/\/en.wikipedia.org\/wiki\/Null_Object_pattern\">\nvery convenient to have a name for the null action<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>John asks why there is a special constant CSIDL_DESKTOP defined for the desktop. After all, in order to use CSIDL_DESKTOP, you need to call SHGet&shy;Desktop&shy;Folder and then bind to it. What&#8217;s the point of having an ITEM&shy;ID&shy;LIST that represents the desktop if, in order to use it, you first need to get the desktop? It&#8217;s [&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":[26],"class_list":["post-9363","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>John asks why there is a special constant CSIDL_DESKTOP defined for the desktop. After all, in order to use CSIDL_DESKTOP, you need to call SHGet&shy;Desktop&shy;Folder and then bind to it. What&#8217;s the point of having an ITEM&shy;ID&shy;LIST that represents the desktop if, in order to use it, you first need to get the desktop? It&#8217;s [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9363","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=9363"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9363\/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=9363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=9363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=9363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}