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


Функция 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 в параметре dwCoIn it . Вы также можете использовать coInitialize или OleInitialize, которые всегда используют потоки квартир. Если требуется функция перетаскивания, рекомендуется OleInitialize, так как она инициализирует необходимый OLE, а также COM.

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

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

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

Если флаг BIF_RETURNONLYFSDIRS установлен в элементе ulFlags член структуры BROWSEINFO, кнопка OK остается включенной для элементов "\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 в ярлык, отправляя 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 [только классические приложения]
целевая платформа Виндоус
заголовка shlobj_core.h (include Shlobj.h, Shlobj_core.h)
библиотеки Shell32.lib
DLL Shell32.dll (версия 4.0 или более поздняя версия)

См. также

Открыть и сохранить в виде диалоговых окон