views:

326

answers:

2

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.

+3  A: 

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;
};
Mordachai
A: 

Mordachai's answer might be correct, but to me this query makes no sense on two fronts:

  1. I don't believe there is a published document saying that an IShellFolder can have only one parent. There might be multiple ways to any particular shell folder. the control panel is accessible via My Computer, via the Start Menu, and anywhere in the file system you create a junction point to it. It seems the shell teams oringinal intention was, given an IShellFolder instance, it should not matter to external users what its arbitrary location happened to be.

  2. Plus, any application that instantiates an IShellFolder surely did so FROM a having knowledge of a PIDL. If your app cared about the path to an IShellFolder it already HAD that information. How did you loose it? (And why should the shell team add a method to help apps keep track of their own data?)

Chris Becke
1. True, but the filesystem is the underlying truth for most objects in the shell space. And although its possible to have multiple links, junctions, etc., to a given folder, there can be only one actual parent folder. Its true by definition of the filesystem. This has always been so, and there is SHBindToParent to corroborate this truth.2. Not so. One can instantiate an IShellFolder directly from SHGetDesktopFolder. At any rate, it is often systems designed that can only go one way that ultimately fail. The ability to convert from one to another is more flexible and robust.
Mordachai
1. So what if some filesystems have limits.The shell namespace was designed to express the more general case.2. Thanks for pointing out the 1 special case. Very clever.
Chris Becke