Search code examples
c++winapicomwindows-shell

How to obtain the PIDL of an IShellFolder


If I have an IShellFolder interface pointer. How might I obtain its PIDL?

I can see how to enumerate its children, and I can see how to use it to compare any two children. But how might I get its own pidl?

I ask because I'd like to know:

Is this IShellFolder == Another IShellFolder

I can use IShellFolder::CompareIDs(), but I have to have the IDs of both folders.


Solution

  • I found that you can query an IShellFolder for its IPersistFolder2, which has GetCurFolder(), which returns its absolute PIDL. I could then simply use the IShellFolder for the desktop to CompareIDs() to determine if they're equal. I found the outlines of this while looking at SHGetIDListFromObject. I couldn't just use that function, because its Vista, and I need XP compatibility.

    Here's a sketch of how it works (assuming you have an ifolder_desktop, and ifolder_other, which are IShellFolder pointers. Pidl is a simple helper that ensures that the IDLISTs are deallocated properly):

    CComQIPtr<IPersistFolder2> ipf2_desktop(ifolder_desktop);
    CComQIPtr<IPersistFolder2> ipf2_folder(ifolder_other);
    
    Pidl pidl_desktop, pidl_folder;
    VERIFY(SUCCEEDED(ipf2_desktop->GetCurFolder(pidl_desktop)));
    VERIFY(SUCCEEDED(ipf2_folder->GetCurFolder(pidl_folder)));
    
    HRESULT hr = ifolder_desktop->CompareIDs(NULL, pidl_desktop, pidl_folder);
    pCmdUI->Enable(SUCCEEDED(hr) && HRESULT_CODE(hr) != 0);
    

    In case anyone is interested in my simple Pidl class:

    class Pidl
    {
    public:
        // create empty
        Pidl() : m_pidl(NULL) { }
    
        // create one of specified size
        explicit Pidl(size_t size) : m_pidl(Pidl_Create(size)) {}
    
        // create a copy of a given PIDL
        explicit Pidl(const ITEMIDLIST * pidl) : m_pidl(Pidl_Copy(pidl)) {}
    
        // create an absolute PIDL from a parent + child
        Pidl(const ITEMIDLIST_ABSOLUTE * pParent, const ITEMIDLIST_RELATIVE * pChild) : m_pidl(Pidl_Concatenate(pParent, pChild)) { }
    
        // return our PIDL for general use (but retain ownership of it)
        operator const ITEMIDLIST * () { return m_pidl; }
    
        // return a pointer to our pointer, for use in functions that assign to a PIDL
        operator ITEMIDLIST ** () 
        {
            free();
            return &m_pidl; 
        }
    
        // release ownership of our PIDL
        ITEMIDLIST * release() 
        { 
            ITEMIDLIST * pidl = m_pidl;
            m_pidl = NULL;
            return pidl;
        }
    
        void free()
        {
            if (m_pidl)
                //Pidl_Free(m_pidl);
                ILFree(m_pidl);
        }
    
        // automatically free our pidl (if we have one)
        ~Pidl()
        {
            free();
        }
    
    private:
        ITEMIDLIST * m_pidl;
    };