Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 289
Mordachai Avatar asked Nov 19 '09 20:11

Mordachai


2 Answers

What either Chris or Mordechai writes on #1 is anyway not to the point. The question is not about objects in the shell namespace but about objects that have an IShellFolder interface. Possession of an IShellFolder interface does not itself imply a presence in the shell namespace. The original question is ill-formed, inasmuch as it assumes that an object with an IShellFolder interface must have "its own PIDL".

The best you can do, I think, is as Mordechai suggests:

  • see if the object also has an IPersistFolder2 interface

The purpose of this interface is to fix the object in the shell namespace, which is in turn what makes the folder persistable. Rather than infer from any absence of published documentation, look at what Microsoft actually does say of the IPersistFolder and IPersistFolder2 interfaces and the Initialize and GetCurFolder methods. Most notably:

you need to implement this interface so that the Shell folder object's ITEMIDLIST can be retrieved.

On #2, I'm afraid Chris is definitely not correct. An IShellFolder certainly can be obtained without a PIDL. The Control Panel, which Chris introduced for #1, provides a ready counter-example for #2. Just feed CLSID_ControlPanel and IID_IShellFolder to CoCreateInstance. You get a perfectly usable instantiation of the Control Panel without ever "having knowledge of a PIDL".

There are a handful of other creatable shell folders implemented in SHELL32, and any DLL can set up any number of others.

like image 154
Geoff Chappell Avatar answered Sep 20 '22 22:09

Geoff Chappell


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;
};
like image 39
Mordachai Avatar answered Sep 20 '22 22:09

Mordachai