Obtenir des informations sur le contenu d'un dossier

La section Obtenir l'ID d'un dossier a abordé deux approches pour obtenir un pointeur vers une liste d'identifiants d'éléments (PIDL) d'un objet de l'espace de noms. Cette section soulève une question évidente : une fois que vous avez un PIDL, comment pouvez-vous l'utiliser ? Parallèlement, une autre question se pose : que se passe-t-il si aucune des deux approches ne fonctionne ou n'est adaptée à votre application ? Pour répondre à ces deux questions, il convient d'examiner de plus près la manière dont l'espace de noms est mis en œuvre. La clé est l'interface IShellFolder.

Utilisation de l'interface IShellFolder

Plus haut dans cette documentation, les dossiers de l'espace de noms ont été appelés objets. Bien qu'à ce stade, le terme ait été utilisé dans un sens large, il est également vrai dans un sens plus restreint. Chaque dossier d'espace de noms est représenté par un objet COM (Component Object Model). Chaque objet de dossier expose un certain nombre d'interfaces qui peuvent être utilisées pour une grande variété de tâches. Certaines interfaces facultatives peuvent ne pas être exposées par tous les dossiers. Toutefois, tous les dossiers doivent exposer l'interface de base, IShellFolder.

La première étape de l'utilisation d'un objet dossier consiste à récupérer un pointeur vers son interface IShellFolder. En plus de fournir l'accès aux autres interfaces de l'objet, IShellFolder expose un groupe de méthodes qui gèrent un certain nombre de tâches courantes, dont plusieurs sont abordées dans cette section.

Pour récupérer un pointeur vers l'interface IShellFolder d'un objet de l'espace de noms, vous devez d'abord appeler SHGetDesktopFolder. Cette fonction renvoie un pointeur vers l'interface IShellFolder de la racine de l'espace de noms, le bureau. Une fois que vous disposez de l'interface IShellFolder du bureau, vous pouvez procéder de différentes manières.

Si vous avez déjà obtenu le PIDL du dossier qui vous intéresse, par exemple en appelant SHGetFolderLocation, vous pouvez récupérer son interface IShellFolder en appelant la méthode IShellFolder::BindToObject du bureau. Si vous détenez le tracé d'un objet du système de fichiers, vous devez d'abord obtenir son PIDL en appelant la méthode IShellFolder::ParseDisplayName du bureau, puis appeler IShellFolder::BindToObject. Si aucune de ces approches n'est applicable, vous pouvez utiliser d'autres méthodes IShellFolder pour naviguer dans l'espace de noms. Pour en savoir plus, reportez-vous à Navigation dans l'espace de noms.

Énumération du contenu d'un dossier

En général, la première chose que vous souhaitez faire avec un dossier est de découvrir son contenu. Vous devez d'abord appeler la méthode IShellFolder::EnumObjects du dossier. Le dossier crée un objet d'énumération OLE standard et renvoie son interface IEnumIDList. Cette interface expose quatre méthodes standard, notamment Cloner, Suivant, Réinitialiser et Ignorer, qui peuvent être utilisées pour énumérer le contenu du dossier.

La procédure de base pour énumérer le contenu d'un dossier est la suivante :

  1. Appelez la méthode IShellFolder::EnumObjects des dossiers pour récupérer un pointeur vers l'interface IEnumIDList d'un objet d'énumération.
  2. Transmettez une PIDL non allouée à IEnumIDList::Next. Suivant se charge d'allouer le PIDL. Toutefois, l'application doit la désallouer lorsqu'elle n'est plus requise. Lorsque Suivant revient, le PIDL ne contient que l'ID de l'objet et les caractères NULL de fin. En d'autres termes, il s'agit d'un PIDL de niveau unique par rapport au dossier, et non d'un PIDL complet.
  3. Répétez l'étape 2 jusqu'à ce que Suivant renvoie S_FALSE pour indiquer que tous les éléments ont été énumérés.
  4. Appelez IEnumIDList::Release pour libérer l'objet d'énumération.

Remarque

Vous devez savoir si vous travaillez avec un PIDL complet ou relatif. Certaines fonctions et méthodes acceptent l'un ou l'autre. Cependant, d'autres n'admettront qu'un ou l'autre.

 

Les trois autres méthodes IEnumIDList (Réinitialiser, Ignorer et Cloner) sont utiles si vous devez effectuer des énumérations répétées du dossier. Elles vous permettent de réinitialiser l'énumération, d'ignorer un ou plusieurs objets et de faire une copie de l'objet d'énumération afin de préserver son état.

Détermination des noms d'affichage et d'autres propriétés

Une fois que vous avez énuméré tous les PIDL contenus dans un dossier, vous pouvez déterminer le type d'objets qu'ils représentent. L'interface IShellFolder fournit un certain nombre de méthodes utiles, dont deux sont abordées ici. D'autres méthodes IShellFolder et d'autres interfaces de dossier Shell sont abordées ultérieurement.

L'une des propriétés les plus utiles est le nom d'affichage de l'objet. Pour récupérer le nom d'affichage d'un objet, transmettez son PIDL à IShellFolder::GetDisplayNameOf. Bien que l'objet puisse être situé n'importe où sous le dossier parent dans l'espace de noms, son PIDL doit être relatif au dossier.

IShellFolder::GetDisplayNameOf renvoie le nom d'affichage dans une structure STRRET. L'extraction du nom d'affichage à partir d'une structure STRRET pouvant s'avérer quelque peu délicate, le Shell fournit deux fonctions qui exécutent cette tâche à votre place, notamment StrRetToStr et StrRetToBuf. Les deux fonctions prennent une structure STRRET et renvoient le nom d'affichage sous la forme d'une chaîne normale. Elles diffèrent uniquement dans la façon dont la chaîne est allouée.

En plus de son nom complet, un objet peut avoir un certain nombre d'attributs. Par exemple, s'agit-il d'un dossier ? Peut-il être déplacé ? Vous pouvez récupérer les attributs d'un objet en transmettant son PIDL à IShellFolder::GetAttributesOf. La liste complète des attributs est assez longue. Il est donc préférable de se reporter à la référence pour en savoir plus. Notez que le PIDL que vous transmettez à GetAttributesOf doit être à un niveau unique. En particulier, IShellFolder::GetAttributesOf accepte les PIDL renvoyés par IEnumIDList::Next. Vous pouvez transmettre un tableau de PIDL et GetAttributesOf renvoie les attributs que tous les objets du tableau ont en commun.

Si vous disposez du tracé complet ou du PIDL d'un objet, SHGetFileInfo fournit un moyen simple de récupérer sur un objet suffisamment d'informations pour de nombreux usages. SHGetFileInfo utilise un tracé complet ou PIDL et renvoie une série d'informations sur l'objet, notamment :

  • le nom d'affichage de l'objet
  • les attributs de l'objet
  • des handles vers les icônes de l'objet
  • un handle vers la liste des images système
  • le tracé du fichier contenant l'icône de l'objet

Obtention d'un pointeur vers l'interface IShellFolder d'un sous-dossier

Vous pouvez déterminer si votre dossier contient des sous-dossiers en appelant IShellFolder::GetAttributesOf et en vérifiant si l'indicateur SFGAO_FOLDER est activé. Si un objet est un dossier, vous pouvez le lier, et vous obtenez ainsi un pointeur sur son interface IShellFolder.

Pour lier un sous-dossier, appelez la méthode IShellFolder::BindToObject du dossier parent. Cette méthode prend le PIDL du sous-dossier et renvoie un pointeur vers son interface IShellFolder. Une fois que vous avez ce pointeur, vous pouvez utiliser les méthodes IShellFolder pour énumérer le contenu des sous-dossiers, déterminer leurs propriétés, etc.

Détermination du dossier parent d'un objet

Si vous disposez du PIDL d'un objet, vous pouvez avoir besoin d'un handle vers l'une des interfaces exposées par son dossier parent. Par exemple, si vous souhaitez déterminer le nom d'affichage associé à une PIDL en utilisant IShellFolder::GetDisplayNameOf, vous devez d'abord récupérer l'interface IShellFolder du parent de l'objet. Les techniques présentées dans les sections précédentes permettent d'y parvenir. Cependant, une approche beaucoup plus simple consiste à utiliser la fonction Shell, SHBindToParent. Cette fonction utilise le PIDL complet d'un objet et renvoie un pointeur d'interface spécifié sur le dossier parent. Elle renvoie également, en option, le PIDL à niveau unique de l'élément pour une utilisation dans des méthodes de type IShellFolder::GetAttributesOf.

L'exemple d'application de console suivant récupère le PIDL du dossier spécial System et renvoie son nom d'affichage.

#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;
}

L'application utilise d'abord SHGetFolderLocation pour récupérer le PIDL du dossier du système. Elle appelle ensuite SHBindToParent, qui renvoie un pointeur vers l'interface IShellFolder du dossier parent et le PIDL du dossier du système par rapport à son parent. Elle utilise ensuite la méthode IShellFolder::GetDisplayNameOf du dossier parent pour récupérer le nom d'affichage du dossier du système. Dans la mesure où GetDisplayNameOf renvoie une structure STRRET, StrRetToBuf est utilisé pour convertir le nom d'affichage en une chaîne de caractères normale. Après l'affichage du nom d'affichage, les pointeurs d'interface sont libérés et le PIDL du système est libéré. Notez que vous ne devez pas libérer le PIDL relatif renvoyé par SHBindToParent.