Implementing Missing Shell Functions
Later versions of the Windows shell have introduced a number of useful helpers that frankly could have done with being there from the start. Luckily, many of these functions are not too hard to implement. For example, SHBindToParent simply walks along an item ID list until it gets to the penultimate item. It then binds to the folder containing the item and returns a pointer to the final item in the ID list. Here is an alternative implementation of SHBindToParent:
 
#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;
}
 
 
Other functions that I may one day get around to implementing include SHParseDisplayName, StrRetToBuf and StrRetToStr.
 
If you spot an error then please let me know, so that I can fix this page. Cheers!
 
Home

Last updated 16 July 2002.

1