Fonction SHBrowseForFolderA (shlobj_core.h)

Affiche une boîte de dialogue qui permet à l’utilisateur de sélectionner un dossier Shell.

Syntaxe

PIDLIST_ABSOLUTE SHBrowseForFolderA(
  [in] LPBROWSEINFOA lpbi
);

Paramètres

[in] lpbi

Type : LPBROWSEINFO

Pointeur vers une structure BROWSEINFO qui contient les informations utilisées pour afficher la boîte de dialogue.

Valeur retournée

Type : PIDLIST_ABSOLUTE

Retourne un PIDL qui spécifie l’emplacement du dossier sélectionné par rapport à la racine de l’espace de noms. Si l’utilisateur choisit le bouton Annuler dans la boîte de dialogue, la valeur de retour est NULL.

Il est possible que le PIDL retourné soit celui d’un raccourci de dossier plutôt que d’un dossier. Pour une discussion complète de ce cas, consultez la section Remarques.

Remarques

Pour Windows Vista ou version ultérieure, il est recommandé d’utiliser IFileDialog avec l’option FOS_PICKFOLDERS plutôt que la fonction SHBrowseForFolder. Cela utilise la boîte de dialogue Ouvrir des fichiers en mode Choisir des dossiers et constitue l’implémentation préférée.

Vous devez initialiser com (Component Object Model) avant d’appeler SHBrowseForFolder. Si vous initialisez COM à l’aide de CoInitializeEx, vous devez définir l’indicateur COINIT_APARTMENTTHREADED dans son paramètre dwCoInit . Vous pouvez également utiliser CoInitialize ou OleInitialize, qui utilisent toujours le thread d’appartement. Si vous avez besoin d’une fonctionnalité glisser-déplacer, OleInitialize est recommandé, car il initialise l’ole requis ainsi que COM.

Note Si COM est initialisé à l’aide de CoInitializeEx avec l’indicateur COINIT_MULTITHREADED, SHBrowseForFolder échoue si l’application appelante utilise l’indicateur BIF_USENEWUI ou BIF_NEWDIALOGSTYLE dans la structure BROWSEINFO .
 
Il incombe à l’application appelante d’appeler CoTaskMemFree pour libérer l’IDList retourné par SHBrowseForFolder quand il n’est plus nécessaire.

Deux styles de boîte de dialogue sont disponibles. L’ancien style est affiché par défaut et n’est pas redimensionnable. Le style le plus récent offre un certain nombre de fonctionnalités supplémentaires, notamment la fonctionnalité glisser-déplacer dans la boîte de dialogue, la réorganisation, la suppression, les menus contextuels, la possibilité de créer de nouveaux dossiers et d’autres commandes de menu contextuel. Initialement, elle est plus grande que l’ancienne boîte de dialogue, mais l’utilisateur peut la redimensionner. Pour spécifier une boîte de dialogue à l’aide du style le plus récent, définissez l’indicateur BIF_USENEWUI dans le membre ulFlags de la structure BROWSEINFO .

Si vous implémentez une fonction de rappel, spécifiée dans le membre lpfn de la structure BROWSEINFO , vous recevez un handle dans la boîte de dialogue. L’une des utilisations de ce handle de fenêtre est de modifier la disposition ou le contenu de la boîte de dialogue. Étant donné qu’elle n’est pas redimensionnable, la modification de l’ancienne boîte de dialogue de style est relativement simple. La modification de la boîte de dialogue de style plus récente est beaucoup plus difficile et n’est pas recommandée. Non seulement il a une taille et une disposition différentes de l’ancien style, mais ses dimensions et les positions de ses contrôles changent chaque fois qu’il est redimensionné par l’utilisateur.

Si l’indicateur BIF_RETURNONLYFSDIRS est défini dans le membre ulFlags de la structure BROWSEINFO , le bouton OK reste activé pour les éléments « \server », ainsi que pour « \server\share » et les éléments d’annuaire. Toutefois, si l’utilisateur sélectionne un élément « \server », la transmission du PIDL retourné par SHBrowseForFolder à SHGetPathFromIDList échoue.

Filtrage personnalisé

À partir de Windows XP, SHBrowseForFolder prend en charge le filtrage personnalisé sur le contenu de la boîte de dialogue. Pour créer un filtre personnalisé, procédez comme suit.
  1. Définissez l’indicateur BIF_NEWDIALOGSTYLE dans le membre ulFlags de la structure BROWSEINFO vers laquelle pointe le paramètre lpbi .
  2. Spécifiez une fonction de rappel dans le membre lpfn de cette même structure BROWSEINFO .
  3. Codez la fonction de rappel pour recevoir les messages BFFM_INITIALIZED et BFFM_IUNKNOWN. À la réception du message BFFM_IUNKNOWN, le paramètre lParam de la fonction de rappel contient un pointeur vers l’implémentation de IUnknown dans la boîte de dialogue. Appelez QueryInterface sur ce IUnknown pour obtenir un pointeur vers un instance de IFolderFilterSite.
  4. Créez un objet qui implémente IFolderFilter.
  5. Appelez IFolderFilterSite ::SetFilter, en lui passant un pointeur vers votre IFolderFilter. Les méthodes IFolderFilter peuvent ensuite être utilisées pour inclure et exclure des éléments de l’arborescence.
  6. Une fois le filtre créé, l’interface IFolderFilterSite n’est plus nécessaire. Appelez IFolderFilterSite ::Release si vous n’avez plus d’utilisation pour elle.

Gestion des raccourcis

Note Cette section s’applique uniquement aux systèmes Windows 2000 et antérieurs. Par défaut, Windows XP et les systèmes ultérieur retournent le PIDL de la cible d’un raccourci plutôt que le raccourci lui-même, tant que l’indicateur BIF_NOTRANSLATETARGETS n’est pas défini dans la structure BROWSEINFO .
 
Si SHBrowseForFolder renvoie un PIDL à un raccourci, l’envoi de ce PIDL à SHGetPathFromIDList retourne le chemin du raccourci lui-même plutôt que le chemin de sa cible. Le chemin d’accès à la cible du raccourci peut être obtenu à l’aide de l’interface IShellLink , comme illustré dans cet exemple.
#include 

// Macros for interface casts
#ifdef __cplusplus
#define IID_PPV_ARG(IType, ppType) IID_##IType, reinterpret_cast(static_cast(ppType))
#else
#define IID_PPV_ARG(IType, ppType) &IID_##IType, (void**)(ppType)
#endif

// Retrieves the UIObject interface for the specified full PIDL
STDAPI SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
{
    LPCITEMIDLIST pidlChild;
    IShellFolder* psf;

    *ppv = NULL;

    HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
    if (SUCCEEDED(hr))
    {
        hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);
        psf->Release();
    }
    return hr;
}
 
#define ILSkip(pidl, cb)       ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
#define ILNext(pidl)           ILSkip(pidl, (pidl)->mkid.cb)
 
HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
{
    DWORD cbTotal = 0;

    if (pidl)
    {
        LPCITEMIDLIST pidl_temp = pidl;
        cbTotal += sizeof (pidl_temp->mkid.cb);

        while (pidl_temp->mkid.cb) 
        {
            cbTotal += pidl_temp->mkid.cb;
            pidl_temp += ILNext (pidl_temp);
        }
    }
    
    *ppidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);
    
    if (*ppidl)
        CopyMemory(*ppidl, pidl, cbTotal);
 
    return  *ppidl ? S_OK: E_OUTOFMEMORY;
}
 
// Get the target PIDL for a folder PIDL. This also deals with cases of a folder  
// shortcut or an alias to a real folder.
STDAPI SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
{
    IShellLink *psl;
	
    *ppidl = NULL;
    
    HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_PPV_ARG(IShellLink, &psl));
    
    if (SUCCEEDED(hr))
    {
        hr = psl->GetIDList(ppidl);
        psl->Release();
    }
    
    // It's not a folder shortcut so get the PIDL normally.
    if (FAILED(hr))
        hr = SHILClone(pidlFolder, ppidl);
    
    return hr;
}

// Get the target folder for a folder PIDL. This deals with cases where a folder
// is an alias to a real folder, folder shortcuts, the My Documents folder, and 
// other items of that nature.
STDAPI SHGetTargetFolderPath(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
{
    LPITEMIDLIST pidlTarget;
	
    *pszPath = 0;

    HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);
    
    if (SUCCEEDED(hr))
    {
        SHGetPathFromIDListW(pidlTarget, pszPath);   // Make sure it is a path
        CoTaskMemFree(pidlTarget);
    }
    
    return *pszPath ? S_OK : E_FAIL;
}

// Retrieves the UIObject interface for the specified full PIDLstatic 
HRESULT SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
{    
    LPCITEMIDLIST pidlChild;    
    IShellFolder* psf;    
    *ppv = NULL;    
    
    HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&psf, &pidlChild);    
    if (SUCCEEDED(hr))    
    {        
        hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);        
        psf->Release();    
    }    
    return hr;
}

static HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
{    
    DWORD cbTotal = 0;    
    if (pidl)
    {        
        LPCITEMIDLIST pidl_temp = pidl;        
        cbTotal += pidl_temp->mkid.cb;        
        
        while (pidl_temp->mkid.cb)         
        {            
            cbTotal += pidl_temp->mkid.cb;            
            pidl_temp = ILNext(pidl_temp);        
        }    
    }    
    
    *ppidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);    
    if (*ppidl)        
        CopyMemory(*ppidl, pidl, cbTotal);    
        
    return  *ppidl ? S_OK: E_OUTOFMEMORY;
}
    
// Get the target PIDL for a folder PIDL. This also deals with cases of a folder  
// shortcut or an alias to a real folder.
static HRESULT SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
{    
    IShellLink *psl;    
    *ppidl = NULL;    
    
    HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_IShellLink, (LPVOID*)&psl);    
    if (SUCCEEDED(hr))    
    {        
        hr = psl->GetIDList(ppidl);        
        psl->Release();    
    }    
    
    // It's not a folder shortcut so get the PIDL normally.    
    if (FAILED(hr))        
        hr = SHILClone(pidlFolder, ppidl);    
    return hr;
}

// Get the target folder for a folder PIDL. This deals with cases where a folder
// is an alias to a real folder, folder shortcuts, the My Documents folder, 
// and so on.
STDAPI SHGetTargetFolderPath(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
{    
    LPITEMIDLIST pidlTarget;    
    *pszPath = 0;    
    
    HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);    
    if (SUCCEEDED(hr))    
    {        
        SHGetPathFromIDListW(pidlTarget, pszPath);   
        
        // Make sure it is a path        
        CoTaskMemFree(pidlTarget);    
    }    
    
    return *pszPath ? S_OK : E_FAIL;
}

Notes

L’en-tête shlobj_core.h définit SHBrowseForFolder en tant qu’alias qui sélectionne automatiquement la version ANSI ou Unicode de cette fonction en fonction de la définition de la constante de préprocesseur UNICODE. La combinaison de l’utilisation de l’alias neutre en encodage avec du code qui n’est pas neutre en encodage peut entraîner des incompatibilités qui entraînent des erreurs de compilation ou d’exécution. Pour plus d’informations, consultez Conventions pour les prototypes de fonction.

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows XP [applications de bureau uniquement]
Serveur minimal pris en charge Windows 2000 Server [applications de bureau uniquement]
Plateforme cible Windows
En-tête shlobj_core.h (inclure Shlobj.h, Shlobj_core.h)
Bibliothèque Shell32.lib
DLL Shell32.dll (version 4.0 ou ultérieure)

Voir aussi

Ouvrir et enregistrer sous des boîtes de dialogue