Obtener información sobre el contenido de una carpeta
En la sección Obtención del identificador de una carpeta se describen dos enfoques para obtener el puntero de un objeto de espacio de nombres a una lista de identificadores de elemento (PIDL). Una pregunta obvia es: una vez que tenga un PIDL, ¿qué puede hacer con él? Una pregunta relacionada es: ¿Qué ocurre si ninguno de los enfoques funciona o es adecuado para la aplicación? La respuesta a ambas preguntas requiere una visión más detallada de cómo se implementa el espacio de nombres. La clave es la interfaz IShellFolder.
- Usar la interfaz IShellFolder
- Enumerar el contenido de una carpeta
- Determinar nombres para mostrar y otras propiedades
- Obtener un puntero a la interfaz IShellFolder de una subcarpeta
- Determinar la carpeta primaria de un objeto
Uso de la interfaz IShellFolder
Anteriormente en esta documentación, las carpetas de espacio de nombres se denominaban objetos. Aunque, en ese momento, el término se usó en un sentido flexible, es realmente cierto en un sentido estricto también. Cada carpeta de espacio de nombres está representada por un objeto del Modelo de objetos componentes (COM). Cada objeto de carpeta expone una serie de interfaces que se pueden usar para una amplia variedad de tareas. Es posible que todas las carpetas no expongan algunas interfaces opcionales. Sin embargo, todas las carpetas deben exponer la interfaz fundamental, IShellFolder.
El primer paso para usar un objeto folder es recuperar un puntero a su interfaz IShellFolder.. Además de proporcionar acceso a las otras interfaces del objeto, IShellFolder expone un grupo de métodos que controlan una serie de tareas comunes, varias de las cuales se describen en esta sección.
Para recuperar un puntero a la interfaz IShellFolder de un objeto de espacio de nombres, primero debe llamar a SHGetDesktopFolder. Esta función devuelve un puntero a la interfaz IShellFolder de la raíz del espacio de nombres, el escritorio. Una vez que tenga la interfaz IShellFolder del escritorio, hay varias maneras de continuar.
Si ya tiene el PIDL de la carpeta que le interesa (por ejemplo, llamando a SHGetFolderLocation), puede recuperar su interfaz IShellFolder llamando al método IShellFolder::BindToObject del escritorio. Si tiene la ruta de acceso de un objeto de sistema de archivos, primero debe obtener su PIDL llamando al método IShellFolder::ParseDisplayName del escritorio y, a continuación, llamar a IShellFolder::BindToObject. Si ninguno de estos enfoques es aplicable, puede usar otros métodos de IShellFolder para navegar por el espacio de nombres. Para obtener más información, vea Navegar por el espacio de nombres.
Enumerar el contenido de una carpeta
Lo primero que normalmente quieres hacer con una carpeta es averiguar lo que contiene. Primero debe llamar al método IShellFolder::EnumObjects de la carpeta. La carpeta creará un objeto de enumeración OLE estándar y devolverá su interfaz IEnumIDList. Esta interfaz expone cuatro métodos estándar (Clonar, Siguiente, Restablecer y Omitir) que se pueden usar para enumerar el contenido de la carpeta.
El procedimiento básico para enumerar el contenido de una carpeta es:
- Llame al método IShellFolder::EnumObjects para recuperar un puntero a la interfaz IEnumIDList de un objeto de enumeración.
- Pase un PIDL sin asignar a IEnumIDList::Next. Siguiente se encarga de asignar el PIDL, pero la aplicación debe desasignarlo cuando ya no sea necesario. Cuando se devuelve Siguiente, el PIDL contendrá solo el identificador de elemento del objeto y los caracteres de NULO de terminación. En otras palabras, es un PIDL de nivel único, relativo a la carpeta, no un PIDL completo.
- Repita el paso 2 hasta que Siguiente devuelva S_FALSE para indicar que se han enumerado todos los elementos.
- Llame a IEnumIDList::Release para liberar el objeto de enumeración.
Nota:
Es importante realizar un seguimiento de si está trabajando con un PIDL completo o relativo. Algunas funciones y métodos aceptarán, pero otras solo tomarán una o la otra.
Los tres métodos IEnumIDList restantes (Restablecer, Omitiry Clonar) son útiles si necesita realizar enumeraciones repetidas de la carpeta. Permiten restablecer la enumeración, omitir uno o varios objetos y realizar una copia del objeto de enumeración para conservar su estado.
Determinar nombres para mostrar y otras propiedades
Una vez que haya enumerado todos los PIDL que contiene una carpeta, puede averiguar qué tipo de objetos representan. La interfaz IShellFolder proporciona una serie de métodos útiles, dos de los cuales se describen aquí. Más adelante se describen otros métodos de IShellFolder y otras interfaces de la carpeta de Shell.
Una de las propiedades más útiles es el nombre para mostrar del objeto. Para recuperar el nombre para mostrar de un objeto, pase su PIDL a IShellFolder::GetDisplayNameOf. Aunque el objeto se puede ubicar en cualquier lugar situado debajo de la carpeta primaria del espacio de nombres, su PIDL debe ser relativo a la carpeta.
IShellFolder::GetDisplayNameOf devuelve el nombre para mostrar como parte de una estructura de STRRET. Debido a que extraer el nombre para mostrar de una estructura STRRET puede ser un poco complicado, Shell proporciona dos funciones que hacen el trabajo por usted, StrRetToStr y StrRetToBuf. Ambas funciones toman una estructura de STRRET y devuelven el nombre para mostrar como una cadena normal. Solo difieren en cómo se asigna la cadena.
Además de su nombre para mostrar, un objeto puede tener varios atributos, como si es una carpeta o si se puede mover. Puede recuperar los atributos de un objeto pasando su PIDL a IShellFolder::GetAttributesOf. La lista completa de atributos es bastante grande, por lo que debería ver la referencia para obtener más información. Tenga en cuenta que el PIDL que pasa a GetAttributesOf debe ser de nivel único. En concreto, IShellFolder::GetAttributesOf aceptará los PIDLs devueltos por IEnumIDList::Next. Puede pasar una matriz de PIDLs y GetAttributesOf devolverá esos atributos que todos los objetos de la matriz tienen en común.
Si tiene una ruta de acceso completa o PIDL de un objeto, SHGetFileInfo proporciona una manera sencilla de recuperar información sobre un objeto que es suficiente para muchos propósitos. SHGetFileInfo toma una ruta de acceso completa o PIDL y devuelve una variedad de información sobre el objeto, entre las que se incluyen:
- Nombre para mostrar del objeto
- Atributos del objeto
- Controla los iconos del objeto
- Identificador de la lista de imágenes del sistema
- Ruta de acceso del archivo que contiene el icono del objeto
Obtención de un puntero a la interfaz IShellFolder de una subcarpeta
Puede determinar si la carpeta contiene subcarpetas llamando a IShellFolder::GetAttributesOf y comprobando si está establecida la marca de SFGAO_FOLDER. Si un objeto es una carpeta, puede enlazarlo, que proporciona un puntero a su interfaz IShellFolder.
Para enlazar a una subcarpeta, llame al método IShellFolder::BindToObject de la carpeta primaria. Este método toma el PIDL de la subcarpeta y devuelve un puntero a su interfaz IShellFolder. Una vez que tenga este puntero, puede usar los métodos IShellFolder para enumerar el contenido de las subcarpetas, determinar sus propiedades y mucho mas.
Determinar la carpeta primaria de un objeto
Si tiene el PIDL de un objeto, es posible que necesite un identificador para una de las interfaces expuestas por su carpeta principal. Por ejemplo, si desea determinar el nombre para mostrar asociado a un PIDL mediante IShellFolder::GetDisplayNameOf, primero debe recuperar la interfaz IShellFolder del elemento primario del objeto. Es posible hacerlo con las técnicas descritas en las secciones anteriores. Sin embargo, un enfoque mucho más sencillo es usar la función Shell, SHBindToParent. Esta función toma el PIDL completo de un objeto y devuelve un puntero de interfaz especificado en la carpeta principal. Opcionalmente, también devuelve el PIDL de nivel único del elemento para su uso en métodos como IShellFolder::GetAttributesOf.
La siguiente aplicación de consola de ejemplo recupera el PIDL de la carpeta especial System y devuelve su nombre para mostrar.
#include <shlobj.h>
#include <shlwapi.h>
#include <iostream.h>
#include <objbase.h>
int main()
{
IShellFolder *psfParent = NULL;
LPITEMIDLIST pidlSystem = NULL;
LPCITEMIDLIST pidlRelative = NULL;
STRRET strDispName;
TCHAR szDisplayName[MAX_PATH];
HRESULT hr;
hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, NULL, &pidlSystem);
hr = SHBindToParent(pidlSystem, IID_IShellFolder, (void **) &psfParent, &pidlRelative);
if(SUCCEEDED(hr))
{
hr = psfParent->GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strDispName);
hr = StrRetToBuf(&strDispName, pidlSystem, szDisplayName, sizeof(szDisplayName));
cout << "SHGDN_NORMAL - " <<szDisplayName << '\n';
}
psfParent->Release();
CoTaskMemFree(pidlSystem);
return 0;
}
La aplicación usa primero SHGetFolderLocation para recuperar el PIDL de la carpeta System. A continuación, llama a SHBindToParent, que devuelve un puntero a la interfaz IShellFolder de la carpeta principal y el PIDL de la carpeta System en relación con su elemento primario. A continuación, usa el método IShellFolder::GetDisplayNameOf de la carpeta primaria para recuperar el nombre para mostrar de la carpeta System. Dado que GetDisplayNameOf devuelve una estructura STRRET, StrRetToBuf se usa para convertir el nombre para mostrar en una cadena normal. Después de mostrar el nombre para mostrar, se liberan los punteros de interfaz y se libera el PIDL del sistema. Tenga en cuenta que no debe liberar el PIDL relativo devuelto por SHBindToParent.