Поделиться через


Функция SHBrowseForFolderA (shlobj_core.h)

Отображает диалоговое окно, позволяющее пользователю выбрать папку оболочки.

Синтаксис

PIDLIST_ABSOLUTE SHBrowseForFolderA(
  [in] LPBROWSEINFOA lpbi
);

Параметры

[in] lpbi

Тип: LPBROWSEINFO

Указатель на структуру BROWSEINFO , содержащую сведения, используемые для отображения диалогового окна.

Возвращаемое значение

Тип: PIDLIST_ABSOLUTE

Возвращает значение PIDL, указывающее расположение выбранной папки относительно корня пространства имен. Если пользователь нажимает кнопку Отмена в диалоговом окне, возвращается значение NULL.

Возможно, возвращаемый PIDL является ярлыком папки, а не папкой. Полное обсуждение этого случая см. в разделе Примечания.

Комментарии

Для Windows Vista или более поздних версий рекомендуется использовать IFileDialog с параметром FOS_PICKFOLDERS, а не функцию SHBrowseForFolder. В этом случае используется диалоговое окно Открыть файлы в режиме выбора папок и является предпочтительной реализацией.

Перед вызовом SHBrowseForFolder необходимо инициализировать компонентную объектную модель (COM). При инициализации COM с помощью CoInitializeEx необходимо задать флаг COINIT_APARTMENTTHREADED в параметре dwCoInit . Вы также можете использовать CoInitialize или OleInitialize, которые всегда используют потоки квартир. Если требуется функция перетаскивания, рекомендуется использовать OleInitialize , так как она инициализирует требуемые OLE и COM.

Примечание Если COM инициализируется с помощью CoInitializeEx с флагом COINIT_MULTITHREADED, shBrowseForFolder завершается ошибкой , если вызывающее приложение использует флаг BIF_USENEWUI или BIF_NEWDIALOGSTYLE в структуре BROWSEINFO .
 
Вызывающее приложение отвечает за вызов CoTaskMemFree , чтобы освободить idList, возвращенный SHBrowseForFolder , когда он больше не нужен.

Существует два стиля диалогового окна. Старый стиль отображается по умолчанию и не может изменяться. Новый стиль предоставляет ряд дополнительных функций, включая возможность перетаскивания в диалоговом окне, изменение порядка, удаление, контекстные меню, возможность создания новых папок и другие команды контекстного меню. Изначально оно больше, чем старое диалоговое окно, но пользователь может изменить его размер. Чтобы указать диалоговое окно в новом стиле, установите флаг BIF_USENEWUI в элементе ulFlags структуры BROWSEINFO .

Если вы реализуете функцию обратного вызова, указанную в элементе lpfn структуры BROWSEINFO , вы получите дескриптор диалогового окна. Одним из способов использования этого дескриптора окна является изменение макета или содержимого диалогового окна. Так как размер окна не изменяется, изменить более старый стиль диалогового окна довольно просто. Изменение нового диалогового окна стиля гораздо сложнее и не рекомендуется. Он не только имеет размер и макет, отличный от старого стиля, но и его размеры и положение элементов управления меняются каждый раз, когда пользователь изменяет его размер.

Если флаг BIF_RETURNONLYFSDIRS установлен в элементе ulFlags структуры BROWSEINFO , кнопка ОК остается включенной для элементов "\server", а также "\server\share" и элементов каталога. Однако если пользователь выбирает элемент \server, передача PIDL, возвращенного SHBrowseForFolder, в SHGetPathFromIDList завершается ошибкой.

Настраиваемая фильтрация

В Windows XP SHBrowseForFolder поддерживает настраиваемую фильтрацию содержимого диалогового окна. Чтобы создать пользовательский фильтр, выполните следующие действия.
  1. Задайте флаг BIF_NEWDIALOGSTYLE в элементе ulFlags структуры BROWSEINFO , на которую указывает параметр lpbi .
  2. Укажите функцию обратного вызова в члене lpfn той же структуры BROWSEINFO .
  3. Код функции обратного вызова для получения сообщений BFFM_INITIALIZED и BFFM_IUNKNOWN. При получении сообщения BFFM_IUNKNOWN параметр lParam функции обратного вызова содержит указатель на реализацию IUnknown в диалоговом окне. Вызовите QueryInterface для этого объекта IUnknown , чтобы получить указатель на экземпляр IFolderFilterSite.
  4. Создайте объект, реализующий IFolderFilter.
  5. Вызовите IFolderFilterSite::SetFilter, передав ему указатель на IFolderFilter. Затем методы IFolderFilter можно использовать для включения и исключения элементов из дерева.
  6. После создания фильтра интерфейс IFolderFilterSite больше не требуется. Вызовите IFolderFilterSite::Release , если вы больше не используете его.

Работа с ярлыками

Примечание Этот раздел относится только к системам Windows 2000 и более ранних версий. По умолчанию системы Windows XP и более поздних версий возвращают PIDL целевого ярлыка, а не самого ярлыка, если флаг BIF_NOTRANSLATETARGETS не задан в структуре BROWSEINFO .
 
Если SHBrowseForFolder возвращает PIDL в ярлык, при отправке этого ФАЙЛА в SHGetPathFromIDList возвращается путь к самому ярлыку, а не путь к его целевому объекту. Путь к целевому объекту ярлыка можно получить с помощью интерфейса IShellLink , как показано в этом примере.
#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;
}

Примечание

Заголовок shlobj_core.h определяет SHBrowseForFolder в качестве псевдонима, который автоматически выбирает версию ANSI или Юникод этой функции на основе определения константы препроцессора ЮНИКОД. Сочетание использования псевдонима, не зависящий от кодировки, с кодом, не зависящим от кодировки, может привести к несоответствиям, которые приводят к ошибкам компиляции или среды выполнения. Дополнительные сведения см. в разделе Соглашения для прототипов функций.

Требования

Требование Значение
Минимальная версия клиента Windows XP [только классические приложения]
Минимальная версия сервера Windows 2000 Server [только классические приложения]
Целевая платформа Windows
Header shlobj_core.h (включая Shlobj.h, Shlobj_core.h)
Библиотека Shell32.lib
DLL Shell32.dll (версия 4.0 или более поздняя)

См. также раздел

Диалоговое окно "Открытие и сохранение как"