#include <ShlObj.h>
#include <ComDef.h>
HRESULT SHBindToParent(
LPCITEMIDLIST pidl,
REFIID riid,
VOID** ppv,
LPCITEMIDLIST* ppidlLast)
{
if (!ppv)
return E_POINTER;
// There must be at least one item ID.
if (!pidl || !pidl->mkid.cb)
return E_INVALIDARG;
// Get the root folder.
IShellFolderPtr desktop;
HRESULT hr = SHGetDesktopFolder(&desktop);
if (FAILED(hr))
return hr;
// Walk to the penultimate item ID.
LPCITEMIDLIST marker = pidl;
for (;;)
{
LPCITEMIDLIST next = reinterpret_cast<LPCITEMIDLIST>(
marker->mkid.abID - sizeof(marker->mkid.cb) + marker->mkid.cb);
if (!next->mkid.cb)
break;
marker = next;
};
if (marker == pidl)
{
// There was only a single item ID, so bind to the root folder.
hr = desktop->QueryInterface(riid, ppv);
}
else
{
// Copy the ID list, truncating the last item.
int length = marker->mkid.abID - pidl->mkid.abID;
if (LPITEMIDLIST parent_id = reinterpret_cast<LPITEMIDLIST>(
malloc(length + sizeof(pidl->mkid.cb))))
{
LPBYTE raw_data = reinterpret_cast<LPBYTE>(parent_id);
memcpy(raw_data, pidl, length);
memset(raw_data + length, 0, sizeof(pidl->mkid.cb));
hr = desktop->BindToObject(parent_id, 0, riid, ppv);
free(parent_id);
}
else
return E_OUTOFMEMORY;
}
// Return a pointer to the last item ID.
if (ppidlLast)
*ppidlLast = marker;
return hr;
}
|