Функция 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.
Существует два стиля диалогового окна. Старый стиль отображается по умолчанию и не может изменяться. Новый стиль предоставляет ряд дополнительных функций, включая возможность перетаскивания в диалоговом окне, изменение порядка, удаление, контекстные меню, возможность создания новых папок и другие команды контекстного меню. Изначально оно больше, чем старое диалоговое окно, но пользователь может изменить его размер. Чтобы указать диалоговое окно в новом стиле, установите флаг BIF_USENEWUI в элементе ulFlags структуры BROWSEINFO .
Если вы реализуете функцию обратного вызова, указанную в элементе lpfn структуры BROWSEINFO , вы получите дескриптор диалогового окна. Одним из способов использования этого дескриптора окна является изменение макета или содержимого диалогового окна. Так как размер окна не изменяется, изменить более старый стиль диалогового окна довольно просто. Изменение нового диалогового окна стиля гораздо сложнее и не рекомендуется. Он не только имеет размер и макет, отличный от старого стиля, но и его размеры и положение элементов управления меняются каждый раз, когда пользователь изменяет его размер.
Если флаг BIF_RETURNONLYFSDIRS установлен в элементе ulFlags структуры BROWSEINFO , кнопка ОК остается включенной для элементов "\server", а также "\server\share" и элементов каталога. Однако если пользователь выбирает элемент \server, передача PIDL, возвращенного SHBrowseForFolder, в SHGetPathFromIDList завершается ошибкой.
Настраиваемая фильтрация
В Windows XP SHBrowseForFolder поддерживает настраиваемую фильтрацию содержимого диалогового окна. Чтобы создать пользовательский фильтр, выполните следующие действия.- Задайте флаг BIF_NEWDIALOGSTYLE в элементе ulFlags структуры BROWSEINFO , на которую указывает параметр lpbi .
- Укажите функцию обратного вызова в члене lpfn той же структуры BROWSEINFO .
- Код функции обратного вызова для получения сообщений BFFM_INITIALIZED и BFFM_IUNKNOWN. При получении сообщения BFFM_IUNKNOWN параметр lParam функции обратного вызова содержит указатель на реализацию IUnknown в диалоговом окне. Вызовите QueryInterface для этого объекта IUnknown , чтобы получить указатель на экземпляр IFolderFilterSite.
- Создайте объект, реализующий IFolderFilter.
- Вызовите IFolderFilterSite::SetFilter, передав ему указатель на IFolderFilter. Затем методы IFolderFilter можно использовать для включения и исключения элементов из дерева.
- После создания фильтра интерфейс IFolderFilterSite больше не требуется. Вызовите IFolderFilterSite::Release , если вы больше не используете его.
Работа с ярлыками
#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 или более поздняя) |