{"id":1503,"date":"2014-03-14T07:00:00","date_gmt":"2014-03-14T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/03\/14\/how-do-i-create-an-ishellitemarray-from-a-bunch-of-file-paths\/"},"modified":"2014-03-14T07:00:00","modified_gmt":"2014-03-14T07:00:00","slug":"how-do-i-create-an-ishellitemarray-from-a-bunch-of-file-paths","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140314-00\/?p=1503","title":{"rendered":"How do I create an IShellItemArray from a bunch of file paths?"},"content":{"rendered":"<p>\nThe <code>IFile&shy;Operation<\/code> interface accepts bulk operations\nin the form of an <code>IShell&shy;Item&shy;Array<\/code>.\nSo how do you take a list of file names and convert them\ninto an\n<code>IShell&shy;Item&shy;Array<\/code>?\n<\/p>\n<p>\nThere is no\n<code>SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;Paths<\/code>\nfunction, but there is a\n<code>SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;ID&shy;Lists<\/code>,\nand we know how to convert a path to an ID list,\nnamely via\n<code>SHParse&shy;Display&shy;Name<\/code>.\nSo lets\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2009\/08\/04\/9856634.aspx\">\nsnap two blocks together<\/a>.\n<\/p>\n<pre>\n#define UNICODE\n#define <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/02\/12\/71851.aspx\">_UNICODE<\/a>\n#define STRICT\n#define <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/01\/24\/10387757.aspx\">STRICT_TYPED_ITEMIDS<\/a>\n#include &lt;windows.h&gt;\n#include &lt;shlobj.h&gt;\n#include &lt;wrl\/client.h&gt;\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/05\/20\/135841.aspx\">class CCoInitialize incorporated by reference<\/a>\ntemplate&lt;typename T&gt;\nHRESULT CreateShellItemArrayFromPaths(\n    UINT ct, T rgt[], IShellItemArray **ppsia)\n{\n *ppsia = nullptr;\n PIDLIST_ABSOLUTE *rgpidl = new(std::nothrow) PIDLIST_ABSOLUTE[ct];\n HRESULT hr = rgpidl ? S_OK : E_OUTOFMEMORY;\n int cpidl;\n for (cpidl = 0; SUCCEEDED(hr) &amp;&amp; cpidl &lt; ct; cpidl++)\n {\n  hr = SHParseDisplayName(rgt[cpidl], nullptr, &amp;rgpidl[cpidl], 0, nullptr);\n }\n if (SUCCEEDED(hr)) {\n  hr = SHCreateShellItemArrayFromIDLists(cpidl, rgpidl, ppsia);\n }\n for (int i = 0; i &lt; cpidl; i++)\n {\n  CoTaskMemFree(rgpidl[i]);\n }\n delete[] rgpidl;\n return hr;\n}\n<\/pre>\n<p>\nThe\n<code>Create&shy;Shell&shy;Item&shy;Array&shy;From&shy;Paths<\/code>\ntemplate function takes an array of paths and starts by creating\na corresponding array of ID lists.\n(If you&#8217;re feeling fancy, you can\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/05\/03\/10415778.aspx\">\nuse a file system bind context to make simple ID lists<\/a>.)\nIt then pumps this array into the\n<code>SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;ID&shy;Lists<\/code>\nfunction to get the item array.\n<\/p>\n<p>\nUsing a template allows you to pass an array of <i>anything<\/i>\nas the array of paths, as long as it has a conversion to\n<code>PCWSTR<\/code>.\nSo you can pass\nan array of <code>PCWSTR<\/code> or\nan array of <code>PWSTR<\/code> or\nan array of <code>BSTR<\/code> or\nan array of <code>CCom&shy;Heap&shy;Ptr&lt;wchar_t&gt;<\/code> or\nan array of <code>CStringW<\/code>\nor whatever else floats your boat.\n<\/p>\n<p>\nLet&#8217;s take this function out for a spin.\n<\/p>\n<pre>\nint __cdecl wmain(int argc, wchar_t **argv)\n{\n CCoInitialize init;\n Microsoft::WRL::ComPtr&lt;IShellItemArray&gt; spsia;\n Microsoft::WRL::ComPtr&lt;IFileOperation&gt; spfo;\n if (SUCCEEDED(CreateShellItemArrayFromPaths(\n                      argc - 1, argv + 1, &amp;spsia)) &amp;&amp;\n     SUCCEEDED(CoCreateInstance(__uuidof(FileOperation), nullptr,\n                      CLSCTX_ALL, IID_PPV_ARGS(&amp;spfo)))) {\n  spfo-&gt;DeleteItems(spsia.Get());\n  spfo-&gt;PerformOperations();\n }\n return 0;\n}\n<\/pre>\n<p>\nThe main program first treats the command line arguments\nas a list of absolute file paths\nand uses our new helper function to create a shell item array\nfrom them.\nIt then passes the shell item array to the\n<code>IFile&shy;Operation::Delete&shy;Items<\/code> method\nto delete all the items.\n<\/p>\n<p>\nNo magic here.\nJust taking the pieces available and combining them in a\nrelatively obvious way.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The IFile&shy;Operation interface accepts bulk operations in the form of an IShell&shy;Item&shy;Array. So how do you take a list of file names and convert them into an IShell&shy;Item&shy;Array? There is no SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;Paths function, but there is a SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;ID&shy;Lists, and we know how to convert a path to an ID list, namely via SHParse&shy;Display&shy;Name. So lets [&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-1503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The IFile&shy;Operation interface accepts bulk operations in the form of an IShell&shy;Item&shy;Array. So how do you take a list of file names and convert them into an IShell&shy;Item&shy;Array? There is no SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;Paths function, but there is a SHCreate&shy;Shell&shy;Item&shy;Array&shy;From&shy;ID&shy;Lists, and we know how to convert a path to an ID list, namely via SHParse&shy;Display&shy;Name. So lets [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1503","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=1503"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1503\/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=1503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=1503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=1503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}