The IFileOperation
interface accepts bulk operations
in the form of an IShellItemArray
.
So how do you take a list of file names and convert them
into an
IShellItemArray
?
There is no
SHCreateShellItemArrayFromPaths
function, but there is a
SHCreateShellItemArrayFromIDLists
,
and we know how to convert a path to an ID list,
namely via
SHParseDisplayName
.
So lets
snap two blocks together.
#define UNICODE #define _UNICODE #define STRICT #define STRICT_TYPED_ITEMIDS #include <windows.h> #include <shlobj.h> #include <wrl/client.h> // class CCoInitialize incorporated by reference template<typename T> HRESULT CreateShellItemArrayFromPaths( UINT ct, T rgt[], IShellItemArray **ppsia) { *ppsia = nullptr; PIDLIST_ABSOLUTE *rgpidl = new(std::nothrow) PIDLIST_ABSOLUTE[ct]; HRESULT hr = rgpidl ? S_OK : E_OUTOFMEMORY; int cpidl; for (cpidl = 0; SUCCEEDED(hr) && cpidl < ct; cpidl++) { hr = SHParseDisplayName(rgt[cpidl], nullptr, &rgpidl[cpidl], 0, nullptr); } if (SUCCEEDED(hr)) { hr = SHCreateShellItemArrayFromIDLists(cpidl, rgpidl, ppsia); } for (int i = 0; i < cpidl; i++) { CoTaskMemFree(rgpidl[i]); } delete[] rgpidl; return hr; }
The
CreateShellItemArrayFromPaths
template function takes an array of paths and starts by creating
a corresponding array of ID lists.
(If you’re feeling fancy, you can
use a file system bind context to make simple ID lists.)
It then pumps this array into the
SHCreateShellItemArrayFromIDLists
function to get the item array.
Using a template allows you to pass an array of anything
as the array of paths, as long as it has a conversion to
PCWSTR
.
So you can pass
an array of PCWSTR
or
an array of PWSTR
or
an array of BSTR
or
an array of CComHeapPtr<wchar_t>
or
an array of CStringW
or whatever else floats your boat.
Let’s take this function out for a spin.
int __cdecl wmain(int argc, wchar_t **argv) { CCoInitialize init; Microsoft::WRL::ComPtr<IShellItemArray> spsia; Microsoft::WRL::ComPtr<IFileOperation> spfo; if (SUCCEEDED(CreateShellItemArrayFromPaths( argc - 1, argv + 1, &spsia)) && SUCCEEDED(CoCreateInstance(__uuidof(FileOperation), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spfo)))) { spfo->DeleteItems(spsia.Get()); spfo->PerformOperations(); } return 0; }
The main program first treats the command line arguments
as a list of absolute file paths
and uses our new helper function to create a shell item array
from them.
It then passes the shell item array to the
IFileOperation::DeleteItems
method
to delete all the items.
No magic here. Just taking the pieces available and combining them in a relatively obvious way.
0 comments