获取文件夹的 ID

在使用命名空间对象之前,需要一种方法来标识它。 这意味着获取其指向项标识符列表的指针 (PIDL) ,如果是文件系统对象,则获取其路径。 本部分讨论获取对象 ID 的两种更简单方法。

若要使用任何文件夹的更强大方法,请使用 IShellFolder 接口。 有关更多详细信息 ,请参阅获取有关文件夹内容的信息

“OpenFiles”对话框

若要使用户能够导航命名空间并选择文件夹,应用程序可以使用 IFileDialog 接口。 使用 FOS_PICKFOLDERS 标志调用此接口会在“选取文件夹”模式下启动 “打开文件 ”公共对话框。

对于 Windows Vista 及更高版本,这是选择文件夹的建议方法。

SHBrowseForFolder 对话框

若要使用户能够导航命名空间并选择文件夹,应用程序只需调用 SHBrowseForFolder 即可。 调用此函数会启动一个具有 UI 的对话框,该 UI 的工作方式与 “打开”或“另存为” 常见对话框类似。

当用户选择文件夹时, SHBrowseForFolder 将返回该文件夹的完全限定的 PIDL 及其显示名称。 如果文件夹位于文件系统中,则应用程序可以通过调用 SHGetPathFromIDList 将 PIDL 转换为路径。 应用程序还可以通过指定根文件夹来限制用户可以从中选择的文件夹范围。 命名空间中仅显示该根目录下的文件夹。 下图显示了 SHBrowseForFolder 对话框,其中根文件夹设置为“程序文件”。

“浏览文件夹”对话框的屏幕截图

稍后提供了有关如何使用 SHBrowseForFolder 的简单示例。

特殊文件夹和 CSIDL

系统将许多常用文件夹指定为 特殊 文件夹。 这些文件夹具有明确定义的用途,其中大多数都存在于所有系统上。 即使它们最初不存在,它们的名称和位置仍会定义,因此以后可以添加它们。 特殊文件夹的集合包括系统的所有标准虚拟文件夹,例如打印机、我的文档和网络邻里。 它还包括许多标准文件系统文件夹,例如 Program Files 和 System。

即使文件夹是所有系统的标准组件,它们在命名空间中的名称和位置也会有所不同。 例如,系统目录在某些系统上为 C:\Winnt\System32,而其他系统上为 C:\Windows\System32。 过去,环境变量提供了一种确定任何特定系统上特殊文件夹的名称和位置的方法。 Shell 现在提供了一种更可靠、更灵活的方法来识别特殊文件夹 、CSIDL。 通常应使用它们,而不是环境变量。

CSIDL 提供了一种统一的方法来标识和查找特殊文件夹,而不考虑它们在特定系统上的名称或位置。 与环境变量不同,CSIDL 可用于虚拟文件夹和文件系统文件夹。 每个特殊文件夹都分配有一个唯一的 CSIDL。 例如,Program Files 文件系统文件夹的 CSIDL 为 CSIDL_PROGRAM_FILES,而 Network Neighborhood 虚拟文件夹的 CSIDL 为 CSIDL_NETWORK

CSIDL 与多个 Shell 函数之一结合使用,以检索特殊文件夹的 PIDL 或特殊文件系统文件夹的路径。 如果该文件夹在系统上不存在,则应用程序可以通过将其 CSIDL 与 CSIDL_FLAG_CREATE组合来强制创建它。 CSIDL 可以传递给以下函数:

请注意,这两个函数是在 Shell 版本 5.0 中引入的,并取代了 SHGetSpecialFolderLocationSHGetSpecialFolderPath 函数。

有关如何使用 CSIDL 和 SHBrowseForFolder 的简单示例

以下示例函数 PidlBrowse 演示了如何使用 CSIDL 检索文件夹的 PIDL,并使用 SHBrowseForFolder 让用户选择文件夹。 它返回所选文件夹的 PIDL 和显示名称。

LPITEMIDLIST PidlBrowse(HWND hwnd, int nCSIDL, LPSTR pszDisplayName)
{
    LPITEMIDLIST pidlRoot = NULL;
    LPITEMIDLIST pidlSelected = NULL;
    BROWSEINFO bi = {0};

    if(nCSIDL)
    {
        SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot);
    }

    else
    {
        pidlRoot = NULL;
    }

    bi.hwndOwner = hwnd;
    bi.pidlRoot = pidlRoot;
    bi.pszDisplayName = pszDisplayName;
    bi.lpszTitle = "Choose a folder";
    bi.ulFlags = 0;
    bi.lpfn = NULL;
    bi.lParam = 0;

    pidlSelected = SHBrowseForFolder(&bi);

    if(pidlRoot)
    {
        CoTaskMemFree(pidlRoot);
    }

    return pidlSelected;
}

调用应用程序传入 SHBrowseForFolder 所需的窗口句柄。 nCSIDL 参数是用于指定根文件夹的可选 CSIDL。 仅显示层次结构中根文件夹下的文件夹。 前面所示的插图是通过调用此函数生成的,其中 nCSIDL 设置为 CSIDL_PROGRAM_FILES。 调用应用程序还会传入字符串缓冲区 pszDisplayName,以保存 PidlBrowse 返回时所选文件夹的显示名称。 调用应用程序负责释放 SHBrowseForFolder 使用 CoTaskMemFree 返回的 IDList。