Função SHBrowseForFolderA (shlobj_core.h)

Exibe uma caixa de diálogo que permite que o usuário selecione uma pasta shell.

Sintaxe

PIDLIST_ABSOLUTE SHBrowseForFolderA(
  [in] LPBROWSEINFOA lpbi
);

Parâmetros

[in] lpbi

Tipo: LPBROWSEINFO

Um ponteiro para uma estrutura BROWSEINFO que contém informações usadas para exibir a caixa de diálogo.

Retornar valor

Tipo: PIDLIST_ABSOLUTE

Retorna um PIDL que especifica o local da pasta selecionada em relação à raiz do namespace. Se o usuário escolher o botão Cancelar na caixa de diálogo, o valor retornado será NULL.

É possível que o PIDL retornado seja o de um atalho de pasta em vez de uma pasta. Para obter uma discussão completa sobre esse caso, consulte a seção Comentários.

Comentários

Para o Windows Vista ou posterior, é recomendável que você use IFileDialog com a opção FOS_PICKFOLDERS em vez da função SHBrowseForFolder. Isso usa a caixa de diálogo Abrir Arquivos no modo escolher pastas e é a implementação preferencial.

Você deve inicializar o COM (Component Object Model) antes de chamar SHBrowseForFolder. Se você inicializar COM usando CoInitializeEx, deverá definir o sinalizador COINIT_APARTMENTTHREADED em seu parâmetro dwCoInit . Você também pode usar CoInitialize ou OleInitialize, que sempre usam threading de apartment. Se você precisar de funcionalidade de arrastar e soltar, o OleInitialize será recomendado porque inicializa o OLE necessário, bem como o COM.

Nota Se COM for inicializado usando CoInitializeEx com o sinalizador COINIT_MULTITHREADED, SHBrowseForFolder falhará se o aplicativo de chamada usar o sinalizador BIF_USENEWUI ou BIF_NEWDIALOGSTYLE na estrutura BROWSEINFO .
 
É responsabilidade do aplicativo de chamada chamar CoTaskMemFree para liberar a IDList retornada por SHBrowseForFolder quando ela não for mais necessária.

Há dois estilos de caixa de diálogo disponíveis. O estilo mais antigo é exibido por padrão e não é redimensionável. O estilo mais recente fornece uma série de recursos adicionais, incluindo a funcionalidade de arrastar e soltar dentro da caixa de diálogo, reordenação, exclusão, menus de atalho, a capacidade de criar novas pastas e outros comandos de menu de atalho. Inicialmente, ele é maior que a caixa de diálogo mais antiga, mas o usuário pode redimensioná-lo. Para especificar uma caixa de diálogo usando o estilo mais recente, defina o sinalizador BIF_USENEWUI no membro ulFlags da estrutura BROWSEINFO .

Se você implementar uma função de retorno de chamada, especificada no membro lpfn da estrutura BROWSEINFO , receberá um identificador para a caixa de diálogo. Um uso desse identificador de janela é modificar o layout ou o conteúdo da caixa de diálogo. Como não é redimensionável, modificar a caixa de diálogo de estilo mais antigo é relativamente simples. Modificar a caixa de diálogo de estilo mais recente é muito mais difícil e não é recomendável. Ele não só tem um tamanho e layout diferentes do estilo antigo, mas suas dimensões e as posições de seus controles mudam sempre que são redimensionadas pelo usuário.

Se o sinalizador BIF_RETURNONLYFSDIRS estiver definido no membro ulFlags da estrutura BROWSEINFO , o botão OK permanecerá habilitado para itens "\server", bem como "\server\share" e itens de diretório. No entanto, se o usuário selecionar um item "\server", a passagem do PIDL retornado por SHBrowseForFolder para SHGetPathFromIDList falhará.

Filtragem personalizada

A partir do Windows XP, SHBrowseForFolder dá suporte à filtragem personalizada no conteúdo da caixa de diálogo. Para criar um filtro personalizado, siga estas etapas.
  1. Defina o sinalizador BIF_NEWDIALOGSTYLE no membro ulFlags da estrutura BROWSEINFO apontada pelo parâmetro lpbi .
  2. Especifique uma função de retorno de chamada no membro lpfn dessa mesma estrutura BROWSEINFO .
  3. Codifique a função de retorno de chamada para receber as mensagens de BFFM_INITIALIZED e BFFM_IUNKNOWN. Ao receber a mensagem BFFM_IUNKNOWN, o parâmetro lParam da função de retorno de chamada contém um ponteiro para a implementação de IUnknown da caixa de diálogo. Chame QueryInterface nesse IUnknown para obter um ponteiro para uma instância de IFolderFilterSite.
  4. Crie um objeto que implemente IFolderFilter.
  5. Chame IFolderFilterSite::SetFilter, passando para ele um ponteiro para o IFolderFilter. Os métodos IFolderFilter podem ser usados para incluir e excluir itens da árvore.
  6. Depois que o filtro é criado, a interface IFolderFilterSite não é mais necessária. Chame IFolderFilterSite::Release se você não tiver mais uso para ele.

Lidando com atalhos

Nota Esta seção se aplica apenas a sistemas Windows 2000 e anteriores. Por padrão, o Windows XP e sistemas posteriores retornam o PIDL do destino de um atalho em vez do atalho em si, desde que o sinalizador BIF_NOTRANSLATETARGETS não seja definido na estrutura BROWSEINFO .
 
Se SHBrowseForFolder retornar um PIDL para um atalho, enviar esse PIDL para SHGetPathFromIDList retornará o caminho do atalho em si, em vez do caminho de seu destino. O caminho para o destino do atalho pode ser obtido usando a interface IShellLink , conforme mostrado neste exemplo.
#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;
}

Observação

O cabeçalho shlobj_core.h define SHBrowseForFolder como um alias que seleciona automaticamente a versão ANSI ou Unicode dessa função com base na definição da constante de pré-processador UNICODE. Misturar o uso do alias neutro de codificação com código que não seja neutro em codificação pode levar a incompatibilidades que resultam em erros de compilação ou de runtime. Para obter mais informações, consulte Convenções para protótipos de função.

Requisitos

Requisito Valor
Cliente mínimo com suporte Windows XP [somente aplicativos da área de trabalho]
Servidor mínimo com suporte Windows 2000 Server [somente aplicativos da área de trabalho]
Plataforma de Destino Windows
Cabeçalho shlobj_core.h (inclua Shlobj.h, Shlobj_core.h)
Biblioteca Shell32.lib
DLL Shell32.dll (versão 4.0 ou posterior)

Confira também

Caixas de diálogo Abrir e Salvar como