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.
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:
IPersistFolder2
interfaceThe 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.
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;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With