在程序中使用库

本主题介绍在程序中使用库时要考虑的一些事项。

本主题内容:

库编程概述

库使用户能够以对他们有意义的方式组织基于文件的内容,不受文件系统组织的限制。 当程序支持库时,它允许用户以对他们有意义的方式查找其内容,同时提供与 Windows 7 用户体验一致的用户界面。 库还使程序能够更轻松地查找存储在不同文件夹或不同计算机上的基于文件的内容。

本部分中的主题介绍如何向程序添加库支持,并利用库提供的新功能。 默认情况下,Windows 7 提供部分此支持。 如果程序不修改它当前使用的通用文件对话框,则它可能需要很少的额外编程来支持库。

本部分介绍库提供的一些关键功能,以及如何在程序中支持这些功能。 利用此信息,你可以决定哪些功能将提供最佳的用户体验。 如果你的程序自定义通用文件对话框,本部分中的信息可以帮助你确定如何使用新的通用文件对话框来使用库并提供 Windows 7 中的等效功能。

使用库编程

Windows Shell 编程模型描述程序如何与 Windows Shell 编程对象交互。 虽然文件系统对象(如文件和目录)由 Windows Shell 对象表示,但并非所有 Windows Shell 对象都由文件系统表示。 例如,库是没有文件系统等效项的 Windows Shell 对象。 在程序中使用 Windows Shell 对象可使程序访问所有 Shell 对象,而不仅仅是文件系统对象。

为了获得最佳结果,程序将使用 Shell 库 API 与库交互并访问其内容。 虽然库包含文件夹和文件等文件系统项,但库不是文件系统项。 因此,文件系统 API 不能用于访问库功能或库内容。

如果现有程序当前使用许多文件系统 API,则程序仍可以利用库功能。 Shell 库 API 可以提供对在库中找到的项的文件系统引用,这些文件系统引用(如文件名和路径)可以传递到现有程序中的现有文件系统 API。

从已知文件夹移动到库

在 Windows 7 之前,通常使用已知文件夹(如“我的文档”文件夹)作为文件保存或文件打开操作中的默认文件夹。 在 Windows 7 中,应使用相应的库,以便用户在程序中拥有与其他 Windows 7 程序(如 Windows 资源管理器)相同的体验。

如果当前在程序中使用 Windows Shell API,则添加库支持非常简单。 例如,如果当前调用 SHGetKnownFolderItem 函数来获取“我的文档”文件夹的位置,则可以将“我的文档已知”文件夹的 KNOWNFOLDERID 值替换为相应库的 KNOWNFOLDERID 值。

下表显示了已知文件夹的 KNOWNFOLDERID 值与 Windows 7 中相应库的 KNOWNFOLDERID 值之间的关系。

已知文件夹 KNOWNFOLDERID 值 库 KNOWNFOLDERID 值
FOLDERID_Documents FOLDERID_DocumentsLibrary
FOLDERID_Pictures FOLDERID_PicturesLibrary
FOLDERID_Music FOLDERID_MusicLibrary
FOLDERID_RecordedTV FOLDERID_RecordedTVLibrary

 

家庭组和共享库

向程序添加库支持将启用对家庭组中共享库的支持。 家庭组由其 KNOWNFOLDERIDFOLDERID_HomeGroup标识。 程序可以通过在调用 IShellLibrary::GetDefaultSaveFolder 方法中设置 DEFAULTSAVEFOLDERTYPE 值来查找标识用户的专用或共享默认保存位置。

将通用文件对话框与库配合使用

使用包含库的通用文件对话框 通用文件对话框已更新为支持 Windows 7 中的库。 下图显示了常见文件对话框在 Windows 7 中的显示方式。

显示库的通用文件对话框的屏幕截图

在 Windows 7 中,如果程序当前显示一个通用文件对话框,并且不更改对话框模板或挂钩其任何事件,它将自动显示该对话框的新 Windows 7 版本。 具体而言,在调用通用文件对话框函数时,OPENFILENAME 结构的 lpfnHookhInstancelpTemplatename 成员必须为 NULL并且OFN_ENABLEHOOKOFN_ENABLETEMPLATE标志必须明确。

在 Windows 7 中, IFileDialog 相关的接口替换了早期版本的 Windows 中使用的通用文件对话框函数。 Windows 7 中仍支持早期常用的文件对话框函数,但它们不提供完整的 Windows 7 用户体验,也不支持库。 IFileDialog 相关接口支持的一些新功能包括:

  • 用户可以访问 Windows 7 Windows 资源管理器支持的文件属性,以搜索和选择文件。
  • 程序可以使用 Shell 命名空间 API 中的接口和方法来处理项。
  • 程序可以使用数据驱动的自定义模型而不是资源文件驱动的自定义模型向公共文件对话框添加新控件。

在以下情况下,应使用 IFileDialog 相关的接口:

  • 你需要在 Windows 7 中为程序自定义通用文件对话框。 这将允许程序使用库并支持自定义对话框。
  • 希望用户能够从通用文件对话框中选择多个文件。 这将确保获取所选对象的正确路径,因为库可以包含存储在不同文件夹中的内容。

有关 IFileDialog 相关接口的详细信息,请参阅:

从用户界面启用库选择

如果你的程序允许用户在 Windows 7 中选择一个文件夹(例如用于导入或导出函数),则它也应该允许用户选择库。 IFileOpenDialog 接口和 SHBrowseForFolder 函数允许用户在提示选择文件夹时选择库。 IFileOpenDialog 接口优先于 SHBrowseForFolder 函数,因为 IFileOpenDialog 支持 Windows 7 用户界面。

若要允许用户在使用 IFileOpenDialog 界面时选择文件夹,请调用 SetOptions 并设置FOS_PICKFOLDERS标志,并确保FOS_FORCEFILESYSTEM标志清晰。

FILEOPENDIALOGOPTIONS fileOptions;

hr = fileOpenDialogBox->GetOptions(&fileOptions);
fileOptions = fileOptions | FOS_PICKFOLDERS | ~FOS_FORCEFILESYSTEM;
hr = fileOpenDialogBox->SetOptions(fileOptions);

若要允许用户在调用 SHBrowseForFolder 函数时选择文件夹,请在 BROWSEINFO 结构的 ulFlags 成员中设置BIF_USENEWUI标志并清除BIF_RETURNONLYFSDIRS标志。

BROWSEINFO    browseInfo;
browseInfo.ulFlags = BIF_USENEWUI | ~BIF_RETURNONLYFSDIRS;
// Set other member values
pidl = SHBrowseForFolder(&browseInfo);

访问程序中的库内容

若要访问库的内容,必须使用 Windows Shell API。 文件系统 API 的函数不能用于访问库内容,因为库不是文件系统对象。 如果程序使用基于文件系统 API 的自定义文件浏览器,它将不能浏览库或访问库内容。

本部分介绍如何访问库内容,以便选择更新程序以使用库的最佳方法。

使用 IShellLibrary 接口访问库内容

程序访问库内容的最简单方法是使用 Shell 库 API。 如果使用的是使用文件系统 API 的程序, 则 Shell 库 API 可以返回库的文件系统文件夹,从而最大限度地减少对现有程序代码的更改。

IShellLibrary *picturesLibrary;

hr = SHLoadLibraryFromKnownFolder(FOLDERID_PicturesLibrary, 
                                  STGM_READ, 
                                  IID_PPV_ARGS(&picturesLibrary));

// picturesLibrary now points to the user's picture library
    
IShellItemArray *pictureFolders; 

hr = pslLibrary->GetFolders(LFF_FORCEFILESYSTEM, IID_PPV_ARGS(&pictureFolders));

// pictureFolders now contains an array of Shell items that
// represent the folders found in the user's pictures library

使用 Shell API 访问库内容

由于库对象是 Shell 编程模型的一部分,因此可以与其他 Windows Shell API 一起使用。 例如,可以使用程序中的 IShellItemIShellFolder 接口以及相关的帮助程序函数来访问库的内容,其方式与枚举文件夹和文件夹内容以使用文件系统 API 访问内容的方式相同。

Windows Shell API 支持两种枚举模式来访问库的内容:

  • 浏览枚举

    浏览枚举是默认枚举模式,枚举库文件夹的内容。 清除SHCONTF_NAVIGATION_ENUM标志以使用此模式。

  • 导航枚举

    导航枚举枚举库文件夹。 设置SHCONTF_NAVIGATION_ENUM标志以使用此模式。

如果程序使用自定义树控件来导航用户的文件夹,在导航枚举模式下枚举文件夹将为你提供库文件夹的列表,该列表与 Windows 资源管理器枚举 Windows 7 中的文件夹的方式一致。

有关如何在程序中使用这些功能的示例,请参阅 Windows SDK 中的 ShellStorage 示例。

在库中保存用户内容

程序可以将用户内容保存到库以及库中的文件夹。 同样,用户可以保存到库中的特定文件夹,也可以直接保存到库中。

每个库都有一个文件夹,该文件夹被指定为默认保存位置。 默认保存位置是在创建库时定义的;但是,用户可以将默认保存位置重新分配为库中的任何文件夹。 虽然用户不需要配置默认保存位置,但他们可以选择更改它。 如果用户删除当前设置为默认保存位置的文件夹,库将自动将库中的下一个文件夹配置为默认保存位置。

可通过多种方式将用户内容保存到库中。

  • Shell API

    如果使用 Shell 编程模型并将由 IShellItem、IStorage 或 IStream 表示的 Shell 项保存到库对象中,则 Shell 项将自动存储在库的默认保存位置中。

  • 文件系统 API

    如果现有程序使用许多文件系统 API 调用,则可以获取定义为库默认保存位置的文件夹的路径。 然后,可以将文件夹路径传递给文件系统 API。

有关如何在程序中使用这些功能的示例,请参阅 Windows SDK 中的 ShellStorage 示例。

支持库中的拖放操作

如果程序支持拖放操作,则应更新这些操作以支持正确的库交互。 如果将文件放入库中,则已删除的文件应保存在默认保存位置。 如果将文件夹放入库中,则已删除的文件夹应作为新文件夹添加到库中。 如果将文件放入非默认保存位置的现有文件夹中,则应将该文件添加到所选文件夹中。

有关如何为程序拖放功能添加库支持的示例,请参阅 Windows SDK 中的 ShellLibraryCommandLine 示例。

与库保持同步

本主题介绍程序如何使其库内容的视图保持最新。

批量更新

由于用户可在程序未运行时以交互方式修改库的文件夹,因此程序在开始发现并存储库的任何更改时,应调用 SHResolveLibrary 。 Shell API 提供 SHResolveLibrary 函数,使程序能够获取库的当前内容以及库可能包含的任何文件夹的当前位置。

请注意, SHResolveLibrary 是一个阻止函数,可能需要很长时间才能返回,具体取决于库中已更改的内容。 因此,不应从 UI 线程调用它。

程序更新为最新版本后,可以注册更改通知以维护当前视图。

Shell API 通知

Windows Shell API 提供 SHChangeNotifyRegister 函数,这是非服务进程在库中收到更改通知的首选方法。

若要使用 Windows Shell API 检测对库中项的更改,请调用 SHChangeNotifyRegister 注册程序,以获取库文件夹中项的更改通知。 如果有任何库或特定库中的更改,此函数可以通知程序。 更改库时,会立即发送通知。

文件系统 API 通知

必须在服务进程中使用文件系统通知。

若要使用文件系统 API 检测对库中项的更改,请枚举库中的文件夹,并为要监视的每个文件夹调用 FindFirstChangeNotification 。 当受监视的文件夹发生更改时,程序将收到通知。 若要查找文件夹中已更改的文件的特定文件,请调用 ReadDirectoryChangesW。 若要检测库说明文件中的更改,请监视包含它的文件夹。 可以在 FOLDERID_Libraries 文件夹中找到库说明文件。 但是,不应打开或修改库说明文件。

关于库

IShellLibrary

Shell 链接

已知文件夹

库说明架构

IID_PPV_ARGS