Función SHBrowseForFolderA (shlobj_core.h)

Muestra un cuadro de diálogo que permite al usuario seleccionar una carpeta shell.

Sintaxis

PIDLIST_ABSOLUTE SHBrowseForFolderA(
  [in] LPBROWSEINFOA lpbi
);

Parámetros

[in] lpbi

Tipo: LPBROWSEINFO

Puntero a una estructura BROWSEINFO que contiene información utilizada para mostrar el cuadro de diálogo.

Valor devuelto

Tipo: PIDLIST_ABSOLUTE

Devuelve un PIDL que especifica la ubicación de la carpeta seleccionada en relación con la raíz del espacio de nombres. Si el usuario elige el botón Cancelar en el cuadro de diálogo, el valor devuelto es NULL.

Es posible que el PIDL devuelto sea el de un acceso directo de carpeta en lugar de una carpeta. Para obtener una explicación completa de este caso, vea la sección Comentarios.

Comentarios

Para Windows Vista o posterior, se recomienda usar IFileDialog con la opción FOS_PICKFOLDERS en lugar de la función SHBrowseForFolder. Usa el cuadro de diálogo Abrir archivos en el modo de selección de carpetas y es la implementación preferida.

Debe inicializar el Modelo de objetos componentes (COM) antes de llamar a SHBrowseForFolder. Si inicializa COM con CoInitializeEx, debe establecer la marca COINIT_APARTMENTTHREADED en su parámetro dwCoInit . También puede usar CoInitialize o OleInitialize, que siempre usa subprocesos de apartamento. Si necesita la funcionalidad de arrastrar y colocar, se recomienda OleInitialize porque inicializa el OLE necesario, así como COM.

Nota Si COM se inicializa con CoInitializeEx con la marca COINIT_MULTITHREADED, SHBrowseForFolder produce un error si la aplicación que realiza la llamada usa la marca BIF_USENEWUI o BIF_NEWDIALOGSTYLE en la estructura BROWSEINFO .
 
Es responsabilidad de la aplicación que realiza la llamada a CoTaskMemFree liberar el IDList devuelto por SHBrowseForFolder cuando ya no sea necesario.

Hay dos estilos de cuadro de diálogo disponibles. El estilo anterior se muestra de forma predeterminada y no se puede cambiar de tamaño. El estilo más reciente proporciona una serie de características adicionales, incluida la funcionalidad de arrastrar y colocar en el cuadro de diálogo, reordenar, eliminar, menús contextuales, la capacidad de crear nuevas carpetas y otros comandos de menú contextual. Inicialmente, es mayor que el cuadro de diálogo anterior, pero el usuario puede cambiar su tamaño. Para especificar un cuadro de diálogo con el estilo más reciente, establezca la marca BIF_USENEWUI en el miembro ulFlags de la estructura BROWSEINFO .

Si implementa una función de devolución de llamada, especificada en el miembro lpfn de la estructura BROWSEINFO , recibirá un identificador para el cuadro de diálogo. Un uso de este identificador de ventana es modificar el diseño o el contenido del cuadro de diálogo. Dado que no se puede cambiar el tamaño, modificar el cuadro de diálogo de estilo anterior es relativamente sencillo. Modificar el cuadro de diálogo de estilo más reciente es mucho más difícil y no se recomienda. No solo tiene un tamaño y un diseño diferentes que el estilo anterior, pero sus dimensiones y las posiciones de sus controles cambian cada vez que el usuario cambia de tamaño.

Si la marca de BIF_RETURNONLYFSDIRS se establece en el miembro ulFlags de la estructura BROWSEINFO , el botón Aceptar permanece habilitado para los elementos "\server", así como "\server\share" y los elementos de directorio. Sin embargo, si el usuario selecciona un elemento "\server", se produce un error al pasar el PIDL devuelto por SHBrowseForFolder a SHGetPathFromIDList .

Filtrado personalizado

A partir de Windows XP, SHBrowseForFolder admite el filtrado personalizado en el contenido del cuadro de diálogo. Para crear un filtro personalizado, siga estos pasos.
  1. Establezca la marca BIF_NEWDIALOGSTYLE en el miembro ulFlags de la estructura BROWSEINFO a la que apunta el parámetro lpbi .
  2. Especifique una función de devolución de llamada en el miembro lpfn de esa misma estructura BROWSEINFO .
  3. Codifica la función de devolución de llamada para recibir los mensajes BFFM_INITIALIZED y BFFM_IUNKNOWN. Al recibir el mensaje de BFFM_IUNKNOWN, el parámetro lParam de la función de devolución de llamada contiene un puntero a la implementación del cuadro de diálogo de IUnknown. Llame a QueryInterface en ese IUnknown para obtener un puntero a una instancia de IFolderFilterSite.
  4. Cree un objeto que implemente IFolderFilter.
  5. Llame a IFolderFilterSite::SetFilter y pase a él un puntero a su IFolderFilter. Los métodos IFolderFilter se pueden usar para incluir y excluir elementos del árbol.
  6. Una vez creado el filtro, ya no se necesita la interfaz IFolderFilterSite . Llame a IFolderFilterSite::Release si no tiene más uso para él.

Tratar con accesos directos

Nota Esta sección solo se aplica a los sistemas Windows 2000 y anteriores. De forma predeterminada, Windows XP y sistemas posteriores devuelven el PIDL del destino de un acceso directo en lugar del acceso directo en sí, siempre y cuando la marca BIF_NOTRANSLATETARGETS no esté establecida en la estructura BROWSEINFO .
 
Si SHBrowseForFolder devuelve un PIDL a un acceso directo, el envío de ese PIDL a SHGetPathFromIDList devuelve la ruta de acceso directo en lugar de la ruta de acceso de su destino. La ruta de acceso al destino del acceso directo se puede obtener mediante la interfaz IShellLink , como se muestra en este ejemplo.
#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;
}

Nota

El encabezado shlobj_core.h define SHBrowseForFolder como alias que selecciona automáticamente la versión ANSI o Unicode de esta función en función de la definición de la constante de preprocesador UNICODE. La combinación del uso del alias neutral de codificación con código que no es neutral de codificación puede dar lugar a errores de coincidencia que dan lugar a errores de compilación o tiempo de ejecución. Para obtener más información, vea Convenciones para prototipos de función.

Requisitos

Requisito Value
Cliente mínimo compatible Windows XP [solo aplicaciones de escritorio]
Servidor mínimo compatible Windows 2000 Server [solo aplicaciones de escritorio]
Plataforma de destino Windows
Encabezado shlobj_core.h (incluya Shlobj.h, Shlobj_core.h)
Library Shell32.lib
Archivo DLL Shell32.dll (versión 4.0 o posterior)

Consulte también

Abrir y guardar como cuadros de diálogo