c++ - Cómo obtener el PIDL de un IShellFolder
winapi com (4)
Olvidé mencionar la función SHGetIDListFromObject
.
Solo está disponible en Windows Vista y versiones posteriores. Tiene la ventaja de ser documentado, aunque de forma escueta. Obtendrá más detalles, por supuesto, de mi propia documentación . Esto muestra que Microsoft conoce dos formas más de obtener un PIDL para un puntero de interfaz arbitraria a un objeto en el espacio de nombres del shell.
Si tengo un puntero de interfaz IShellFolder
. ¿Cómo puedo obtener su PIDL?
Puedo ver cómo enumerar a sus hijos, y puedo ver cómo usarlo para comparar dos niños. ¿Pero cómo podría obtener su propio pidl?
Lo pregunto porque me gustaría saber:
Es este IShellFolder == Otro IShellFolder
Puedo usar IShellFolder::CompareIDs()
, pero tengo que tener los ID de ambas carpetas.
Descubrí que puede consultar un IShellFolder para su IPersistFolder2, que tiene GetCurFolder (), que devuelve su PIDL absoluto. Podría simplemente usar el IShellFolder para el escritorio para CompareIDs () para determinar si son iguales. Encontré los contornos de esto mientras miraba SHGetIDListFromObject . No podría usar esa función simplemente porque es Vista y necesito compatibilidad con XP.
Aquí hay un bosquejo de cómo funciona (suponiendo que tiene ifolder_desktop, y ifolder_other, que son punteros de IShellFolder. Pidl es un simple ayudante que asegura que los IDLIST se desasignan correctamente):
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);
En caso de que alguien esté interesado en mi clase simple de Pidl:
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;
};
La respuesta de Mordachai podría ser correcta, pero para mí esta consulta no tiene sentido en dos frentes:
No creo que haya un documento publicado que indique que un IShellFolder solo puede tener un padre. Puede haber varias formas de una carpeta de shell particular. se puede acceder al panel de control a través de Mi PC, a través del menú Inicio, y desde cualquier lugar del sistema de archivos se crea un punto de unión. Parece que la intención oringinal de los equipos de shell era que, dada una instancia de IShellFolder, no debería importarles a los usuarios externos cuál era su ubicación arbitraria.
Además, cualquier aplicación que ejemplifique un IShellFolder seguramente lo hizo DESDE tener conocimiento de un PIDL. Si su aplicación se interesó por la ruta de acceso a un IShellFolder, ya TENÍA esa información. ¿Cómo lo perdiste? (¿Y por qué el equipo shell debería agregar un método para ayudar a las aplicaciones a realizar un seguimiento de sus propios datos?)
Lo que Chris o Mordechai escriben en el n. ° 1 de todos modos no va al grano. La pregunta no es sobre objetos en el espacio de nombres del shell sino sobre objetos que tienen una interfaz IShellFolder. La posesión de una interfaz IShellFolder no implica una presencia en el espacio de nombres del shell. La pregunta original está mal formada, en la medida en que asume que un objeto con una interfaz IShellFolder debe tener "su propia PIDL".
Lo mejor que puedes hacer, creo, es lo que sugiere Mordechai: ver si el objeto también tiene una interfaz IPersistFolder2. El propósito de esta interfaz es arreglar el objeto en el espacio de nombres del shell, que a su vez es lo que hace que la carpeta sea persistente. En lugar de inferir de la ausencia de documentación publicada, observe lo que Microsoft realmente dice de las interfaces IPersistFolder e IPersistFolder2 y los métodos Initialize y GetCurFolder. En particular, "debe implementar esta interfaz para poder recuperar la ITEMIDLIST del objeto de la carpeta Shell".
En el n. ° 2, me temo que Chris definitivamente no es correcto. Un IShellFolder ciertamente se puede obtener sin un PIDL. El Panel de control, que Chris introdujo para el n. ° 1, proporciona un contraemplo listo para el n. ° 2. Simplemente envíe CLSID_ControlPanel e IIS_IShellFolder a CoCreateInstance. Obtiene una instancia perfectamente utilizable del Panel de control sin tener nunca "conocimiento de un PIDL". Hay un puñado de otras carpetas de shell creables implementadas en SHELL32, y cualquier DLL puede configurar cualquier cantidad de otras.