{"id":5363,"date":"2013-02-04T07:00:00","date_gmt":"2013-02-04T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/02\/04\/obtaining-the-parsing-name-and-pidl-for-a-random-shell-object\/"},"modified":"2013-02-04T07:00:00","modified_gmt":"2013-02-04T07:00:00","slug":"obtaining-the-parsing-name-and-pidl-for-a-random-shell-object","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130204-00\/?p=5363","title":{"rendered":"Obtaining the parsing name (and pidl) for a random shell object"},"content":{"rendered":"<p><P>\nThe parsing name for a shell item is handy,\nbecause it lets you regenerate the item later.\nActually, the pidl for the shell item is even better,\nbecause that is the official way of saving and restoring objects.\nIt&#8217;s the pidl that gets saved in a shortcut,\nand since shortcuts can be copied around from machine to machine,\npidls must be transportable and forward compatible.\n(A shortcut file created on Windows&nbsp;XP needs to keep working\non all future versions of Windows.)\n<\/P>\n<P>\nHere&#8217;s a handy little tool for grabbing the parsing name and pidl\nfor a random shell object.\nStart with our\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/A>,\nand add in the\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/05\/03\/10006065.aspx\">\n<CODE>Simple&shy;Drop&shy;Target<\/CODE><\/A>\nclass, with the following tweaks:\n<\/P>\n<PRE>\npublic:\n SimpleDropTarget() : m_cRef(1) { <FONT COLOR=\"red\"><STRIKE>\/* g_ppr-&gt;AddRef(); *\/<\/STRIKE><\/FONT> }\n ~SimpleDropTarget() { <FONT COLOR=\"red\"><STRIKE>g_ppr-&gt;Release();<\/STRIKE><\/FONT> }<\/p>\n<p>&#8230;\n \/\/ *** IDropTarget ***\n STDMETHODIMP DragEnter(IDataObject *pdto,\n    DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)\n {\n  *pdwEffect &amp;= <FONT COLOR=\"blue\">DROPEFFECT_LINK<\/FONT>;\n  return S_OK;\n }<\/p>\n<p> STDMETHODIMP DragOver(DWORD grfKeyState,\n   POINTL ptl, DWORD *pdwEffect)\n {\n  *pdwEffect &amp;= <FONT COLOR=\"blue\">DROPEFFECT_LINK<\/FONT>;\n  return S_OK;\n }\n&#8230;\n};\n<\/PRE>\n<P>\nWe are not a COM local server,\nso we won&#8217;t worry about managing our process reference.\nAnd we will accept anything that has a pidl,\nso we say that we will accept objects via linking.\n(The original code accepted by copying,\nwhich would have made us reject non-copyable objects.)\n<\/P>\n<P>\nNow we can hook these up to our scratch program.\n<\/P>\n<PRE>\nBOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n  <FONT COLOR=\"blue\">g_hwndChild = CreateWindow(\n      TEXT(&#8220;edit&#8221;), nullptr, ES_MULTILINE |\n      WS_CHILD | WS_VISIBLE | WS_TABSTOP,\n      0, 0, 0,0, hwnd, (HMENU)1, g_hinst, 0);\n  SimpleDropTarget *psdt = new(std::nothrow) SimpleDropTarget();\n  if (psdt) {\n    RegisterDragDrop(hwnd, psdt);\n    psdt-&gt;Release();\n  }<\/FONT>\n  return TRUE;\n}<\/p>\n<p>void\nOnDestroy(HWND hwnd)\n{\n  <FONT COLOR=\"blue\">RevokeDragDrop(hwnd);<\/FONT>\n  PostQuitMessage(0);\n}<\/p>\n<p>&#8230;\n    \/\/ Change CoInitialize and CoUninitialize to Ole\n    if (SUCCEEDED(<FONT COLOR=\"blue\">OleInitialize<\/FONT>(NULL))) {\n&#8230;\n        <FONT COLOR=\"blue\">OleUninitialize();<\/FONT>\n<\/PRE>\n<P>\nFinally, we need to say what to do when the drop occurs.\n<\/P>\n<PRE>\nvoid AppendText(LPCWSTR psz)\n{\n  SendMessageW(g_hwndChild, EM_REPLACESEL, 0, (LPARAM)psz);\n}<\/p>\n<p>void OpenFilesFromDataObject(IDataObject *pdto)\n{\n  CComPtr&lt;IShellItemArray&gt; spsia;\n  if (SUCCEEDED(SHCreateShellItemArrayFromDataObject(\n                                  pdto, IID_PPV_ARGS(&amp;spsia)))) {\n    CComPtr&lt;IEnumShellItems&gt; spenum;\n    spsia-&gt;EnumItems(&amp;spenum);\n    if (spenum) {\n      for (CComPtr&lt;IShellItem&gt; spsi;\n           spenum-&gt;Next(1, &amp;spsi, nullptr) == S_OK;\n           spsi.Release()) {\n        CComHeapPtr&lt;wchar_t&gt; spszName;\n        if (SUCCEEDED(spsi-&gt;GetDisplayName(\n                     SIGDN_DESKTOPABSOLUTEPARSING, &amp;spszName))) {\n          AppendText(spszName);\n          AppendText(L&#8221;\\r\\n&#8221;);\n        }\n        CComHeapPtr&lt;ITEMIDLIST_ABSOLUTE&gt; spidl;\n        if (SUCCEEDED(CComQIPtr&lt;IPersistIDList&gt;(spsi)-&gt;\n                                            GetIDList(&amp;spidl))) {\n          UINT cb = ILGetSize(spidl);\n          BYTE *pb = reinterpret_cast&lt;BYTE *&gt;\n                          (static_cast&lt;PIDLIST_ABSOLUTE&gt;(spidl));\n          for (UINT i = 0; i &lt; cb; i++) {\n            WCHAR szHex[4];\n            StringCchPrintf(szHex, ARRAYSIZE(szHex),\n                            L&#8221;%02X &#8220;, pb[i]);\n            AppendText(szHex);\n          }\n          AppendText(L&#8221;\\r\\n&#8221;);\n        }\n      }\n    }\n  }\n}\n<\/PRE>\n<P>\nWhen the drop occurs, we convert the data object into a shell\nitem array, enumerate the items, and print the parsing name\nfor the item\nas well as a hex dump of the pidl associated with the item.\n<\/P>\n<P>\nI guess we need some header files.\n<\/P>\n<PRE>\n#include &lt;shlobj.h&gt;\n#include &lt;strsafe.h&gt;\n#include &lt;atlbase.h&gt;\n#include &lt;atlalloc.h&gt;\n<\/PRE>\n<P>\nRun this program and drop the Recycle Bin onto it, say.\n<\/P>\n<PRE>\n::{645FF040-5081-101B-9F08-00AA002F954E}\n14 00 1F 78 40 F0 5F 64 81 50 1B 10 9F 08 00 AA 00 2F 95 4E 00 00 \n<\/PRE>\n<P>\nThis tells you two things.\nFirst, that if you want to generate the Recycle Bin\nfrom a parsing name,\nyou can use that string that starts with two colons.\n<\/P>\n<PRE>\nvar shell = new ActiveXObject(&#8220;Shell.Application&#8221;);\nvar recycleBin = shell.Namespace(\n      &#8220;::{645FF040-5081-101B-9F08-00AA002F954E}&#8221;);\nvar items = recycleBin.Items();\nfor (var i = 0; i &lt; items.Count; i++) {\n WScript.StdOut.WriteLine(items.Item(i));\n}\n<\/PRE>\n<P>\nOf course, there is a predefined enumeration for the Recycle\nBin, so this was a bit of a waste.\nYou could&#8217;ve just written\n<\/P>\n<PRE>\nvar recycleBin = shell.Namespace(10);\n<\/PRE>\n<P>\nBut this technique generalizes to other locations in the shell\nnamespace that do not have a special shorthand value.\n<\/P>\n<P>\nThe second thing the program tells you is that if you want\nto generate the Recycle Bin from a pidl,\nyou can just use that chunk of bytes.\nOkay, that&#8217;s not quite so interesting from a scripting point of view,\nbut if you&#8217;re manipulating pidls,\nthis can be quite handy.\n<\/P>\n<P>\nWe&#8217;ll use this program a little bit in a few weeks,\nbut at this point, it&#8217;s just a &#8220;Little Program&#8221; for today.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The parsing name for a shell item is handy, because it lets you regenerate the item later. Actually, the pidl for the shell item is even better, because that is the official way of saving and restoring objects. It&#8217;s the pidl that gets saved in a shortcut, and since shortcuts can be copied around from [&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-5363","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The parsing name for a shell item is handy, because it lets you regenerate the item later. Actually, the pidl for the shell item is even better, because that is the official way of saving and restoring objects. It&#8217;s the pidl that gets saved in a shortcut, and since shortcuts can be copied around from [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/5363","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=5363"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/5363\/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=5363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=5363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=5363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}