SHBrowseForFolderW 函数 (shlobj_core.h)
显示允许用户选择 Shell 文件夹的对话框。
语法
PIDLIST_ABSOLUTE SHBrowseForFolderW(
[in] LPBROWSEINFOW lpbi
);
参数
[in] lpbi
类型: LPBROWSEINFO
指向 BROWSEINFO 结构的指针,该结构包含用于显示对话框的信息。
返回值
类型: PIDLIST_ABSOLUTE
返回一个 PIDL,指定所选文件夹相对于命名空间根目录的位置。 如果用户在对话框中选择“ 取消 ”按钮,则返回值为 NULL。
返回的 PIDL 可能是文件夹快捷方式而不是文件夹的。 有关此情况的完整讨论,请参阅“备注”部分。
注解
对于 Windows Vista 或更高版本,建议将 IFileDialog 与 FOS_PICKFOLDERS 选项一起使用,而不是 SHBrowseForFolder 函数。 这会在选取文件夹模式下使用“打开文件”对话框,并且是首选实现。
在调用 SHBrowseForFolder 之前,必须 (COM) 初始化组件对象模型。 如果使用 CoInitializeEx 初始化 COM,则必须在其 dwCoInit 参数中设置COINIT_APARTMENTTHREADED标志。 还可以使用 CoInitialize 或 OleInitialize,它们始终使用单元线程。 如果需要拖放功能,建议使用 OleInitialize ,因为它初始化所需的 OLE 和 COM。
有两种可用的对话框样式。 较旧的样式默认显示,且不可调整大小。 较新的样式提供了许多附加功能,包括对话框中的拖放功能、重新排序、删除、快捷菜单、创建新文件夹的功能以及其他快捷菜单命令。 最初,它比旧对话框大,但用户可以调整其大小。 若要使用较新的样式指定对话框,请在 BROWSEINFO 结构的 ulFlags 成员中设置BIF_USENEWUI标志。
如果实现在 BROWSEINFO 结构的 lpfn 成员中指定的回调函数,则会收到对话框的句柄。 此窗口句柄的一个用途是修改对话框的布局或内容。 由于它不可调整大小,因此修改旧样式对话框相对简单。 修改较新的样式对话框要困难得多,不建议这样做。 它不仅具有与旧样式不同的大小和布局,而且每次用户调整其大小时,其控件的尺寸和位置都会发生变化。
如果在 BROWSEINFO 结构的 ulFlags 成员中设置了BIF_RETURNONLYFSDIRS标志,则“确定”按钮仍对“\server”项以及“\server\share”和目录项保持启用状态。 但是,如果用户选择“\server”项,将 SHBrowseForFolder 返回的 PIDL 传递到 SHGetPathFromIDList 会失败。
自定义筛选
从 Windows XP 起, SHBrowseForFolder 支持对对话框内容进行自定义筛选。 若要创建自定义筛选器,请执行以下步骤。- 在 lpbi 参数指向的 BROWSEINFO 结构的 ulFlags 成员中设置BIF_NEWDIALOGSTYLE标志。
- 在同一 BROWSEINFO 结构的 lpfn 成员中指定回调函数。
- 编写回调函数以接收BFFM_INITIALIZED和BFFM_IUNKNOWN消息。 收到BFFM_IUNKNOWN消息后,回调函数的 lParam 参数包含指向对话框实现 IUnknown 的指针。 在该 IUnknown 上调用 QueryInterface 以获取指向 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 定义为别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将非特定编码别名与非非特定编码的代码混合使用可能会导致不匹配,从而导致编译或运行时错误。 有关详细信息,请参阅 函数原型的约定。
要求
要求 | 值 |
---|---|
最低受支持的客户端 | Windows XP [仅限桌面应用] |
最低受支持的服务器 | Windows 2000 Server [仅限桌面应用] |
目标平台 | Windows |
标头 | shlobj_core.h (包括 Shlobj.h、Shlobj_core.h) |
Library | Shell32.lib |
DLL | Shell32.dll (4.0 或更高版本) |