实现基本文件夹对象接口

实现命名空间扩展的过程类似于任何其他进程内组件对象模型 (COM) 对象的过程。 所有扩展必须支持三个主要接口,这些接口为 Windows 资源管理器提供在树视图中显示扩展文件夹所需的基本信息。 但是,若要充分利用 Windows 资源管理器的功能,扩展还必须公开一个或多个支持更复杂的功能的可选接口,例如快捷菜单或拖放,并提供文件夹视图。

本文档讨论如何实现 Windows 资源管理器调用的主接口和可选接口,以获取有关扩展内容的信息。 有关如何实现文件夹视图以及如何自定义 Windows 资源管理器的讨论,请参阅 实现文件夹视图

基本实现和注册

作为进程内 COM 服务器,DLL 必须公开多个标准函数和接口:

这些函数和接口的实现方式与大多数其他 COM 对象的实现方式相同。 有关详细信息,请参阅 COM 文档

注册扩展

与所有 COM 对象一样,必须为扩展创建一个类标识符 (CLSID) GUID。 通过为扩展的CLSID 创建名为 HKEY_CLASSES_ROOT\ CLSID 的子项来注册对象。 DLL 应注册为进程内服务器,并应指定单元线程模型。 可以通过向扩展的 CLSID 键添加各种子项和值来自定义扩展的根文件夹的行为。

其中几个值仅适用于具有虚拟交汇点的扩展。 这些值不适用于其交接点为文件系统文件夹的扩展。 有关进一步的讨论,请参阅 指定命名空间扩展的位置。 若要修改具有虚拟交接点的扩展的行为,请将以下一个或多个值添加到扩展的 CLSID 键:

  • WantsFORPARSING。 具有虚拟交接点的扩展解析名称通常采用 ::{GUID}格式。 此类型的扩展通常包含虚拟项。 但是,某些扩展(如“我的文档”)实际上对应于文件系统文件夹,即使它们具有虚拟交接点。 如果扩展以这种方式表示文件系统对象,则可以设置 WantsFORPARSING 值。 然后,Windows 资源管理器将通过调用文件夹对象的 IShellFolder::GetDisplayNameOf 方法请求根文件夹分析名称,其中 uFlags 设置为 SHGDN_FORPARSINGpidl 设置为指向 PIDL) 项标识符列表 (的单个空指针。 空 PIDL 仅包含终止符。 然后,方法应返回根文件夹的 ::{GUID} 分析名称。
  • HideFolderVerbs。 在 HKEY_CLASSES_ROOT\Folder 下注册的谓词通常与所有扩展相关联。 它们显示在扩展的快捷菜单上,可由 ShellExecute 调用。 若要防止这些谓词中的任何一个与扩展相关联,请设置 HideFolderVerbs 值。
  • HideAsDelete。 如果用户尝试删除你的扩展,Windows 资源管理器将改为隐藏该扩展。
  • HideAsDeletePerUser。 此值与 HideAsDelete 具有相同的效果,但基于每个用户。 仅对尝试删除该扩展的用户隐藏该扩展。 该扩展对所有其他用户可见。
  • QueryForOverlay。 设置此值以指示根文件夹的图标可以具有图标覆盖。 文件夹对象必须支持 IShellIconOverlay 接口。 在 Windows 资源管理器显示根文件夹的图标之前,它将通过调用将 pidlItem 设置为空 PIDL 的两个 IShellIconOverlay 方法之一来请求覆盖图标。

其余值和子项适用于所有扩展:

  • 若要指定扩展的交接点文件夹的显示名称,请将扩展的 CLSID 子项的默认值设置为适当的字符串。
  • 当光标悬停在某个文件夹上时,通常会显示一个描述该文件夹内容的信息提示。 若要为扩展的根文件夹提供信息提示,请为扩展的 CLSID 键创建信息提示 REG_SZ 值,并将其设置为适当的字符串。
  • 若要为扩展的根文件夹指定自定义图标,请创建名为 DefaultIcon 的扩展 CLSID 子项的子项。 将 DefaultIcon 的默认值设置为 REG_SZ 值,该值包含包含图标的文件的名称,后跟逗号,后跟减号,后跟该文件中图标的索引。
  • 默认情况下,扩展的根文件夹的快捷菜单将包含 HKEY_CLASSES_ROOT\Folder下定义的项。 如果设置了相应的SFGAO_XXX标志,则会添加“删除”、“重命名”和“属性”项。 可以将其他项目添加到根文件夹的快捷菜单,或替代现有项,就像对 文件类型一样。 在扩展的 CLSID 键下创建 Shell 子项,并定义扩展 快捷菜单中所述的命令。
  • 如果需要一种更灵活的方法来处理根文件夹的快捷菜单,则可以实现 快捷菜单处理程序。 若要注册快捷菜单处理程序,请在扩展的 CLSID 键下创建 ShellEx 键。 像注册常规 Creating Shell 扩展处理程序一样注册处理程序的 CLSID。
  • 若要将页面添加到根文件夹的属性属性表,请为文件夹提供 SFGAO_HASPROPSHEET 属性并实现 属性表处理程序。 若要注册属性表处理程序,请在扩展的 CLSID 键下创建 ShellEx 键。 像注册常规 Creating Shell 扩展处理程序一样注册处理程序的 CLSID。
  • 若要指定根文件夹的属性,请将 ShellFolder 子项添加到扩展的 CLSID 子项。 创建 Attributes 值,并将其设置为 SFGAO_XXX 标志的相应组合。

下表列出了根文件夹的一些常用属性。

标志 说明
SFGAO_FOLDER 0x20000000 扩展的根文件夹包含一个或多个项目。
SFGAO_HASSUBFOLDER 0x80000000 扩展的根文件夹包含一个或多个子文件夹。 Windows 资源管理器将在文件夹图标旁边放置加号 ( + ) 。
SFGAO_CANDELETE 0x00000020 用户可以删除扩展的根文件夹。 文件夹的快捷菜单将包含 “删除” 项。 应为放置在其中一个 虚拟文件夹下的交接点设置此标志。
SFGAO_CANRENAME 0x00000010 用户可以重命名扩展的根文件夹。 文件夹的快捷菜单将包含 “重命名” 项。
SFGAO_HASPROPSHEET 0x00000040 扩展的根文件夹具有 Properties 属性表。 文件夹的快捷菜单将具有 “属性” 项。 若要提供属性表,必须实现 属性表处理程序。 如前所述,在扩展的 CLSID 密钥下注册处理程序。

 

以下示例显示了显示名称为 MyExtension 的扩展的 CLSID 注册表项。 扩展具有一个自定义图标,该图标包含在扩展的 DLL 中,索引为 1。 设置 SFGAO_FOLDERSFGAO_HASSUBFOLDERSFGAO_CANDELETE 属性。

HKEY_CLASSES_ROOT
   CLSID
      {Extension CLSID}
         (Default) = MyExtension
         InfoTip = Some appropriate text
      DefaultIcon
         (Default) = c:\MyDir\MyExtension.dll,-1
      InProcServer32
         (Default) = c:\MyDir\MyExtension.dll
         ThreadingModel = Apartment
      ShellFolder
         Attributes = 0xA00000020

处理 PIDL

Shell 命名空间中的每个项都必须具有唯一的 PIDL。 Windows 资源管理器将 PIDL 分配给根文件夹,并在初始化期间将该值传递给扩展。 然后,扩展负责为其每个对象分配构造正确的 PIDL,并应请求将这些 PIDL 提供给 Windows 资源管理器。 当 Shell 使用 PIDL 来标识扩展的对象之一时,扩展必须能够解释 PIDL 并识别特定对象。 扩展还必须为每个对象分配显示名称和分析名称。 由于几乎每个文件夹接口都使用 PIDL,因此扩展通常实现单个 PIDL 管理器 来处理所有这些任务。

术语 PIDL 是 ITEMIDLIST 结构或指向此类结构的指针的缩写,具体取决于上下文。 如声明的那样, ITEMIDLIST 结构具有单个成员,即 SHITEMID 结构。 对象的 ITEMIDLIST 结构实际上是包含两个或多个 SHITEMID 结构的打包数组。 这些结构的顺序定义通过命名空间的路径,其方式与 c:\MyDirectory\MyFile 定义通过文件系统的路径大致相同。 通常,对象的 PIDL 将包含一系列 SHITEMID 结构,这些结构对应于定义命名空间路径的文件夹,后跟对象的 SHITEMID 结构,后跟终止符。

终止符是 SHITEMID 结构, cb 成员设置为 NULL。 终止符是必需的,因为对象的 PIDL 中的 SHITEMID 结构数取决于对象在 Shell 命名空间中的位置以及路径的起点。 此外,各种 SHITEMID 结构的大小可能有所不同。 收到 PIDL 时,无法确定其大小,甚至 无法确定 SHITEMID 结构的总数。 相反,必须按结构“遍历”打包数组,直到到达终止符。

若要创建 PIDL,应用程序需要:

  1. 为其每个对象创建 SHITEMID 结构。
  2. 将相关的 SHITEMID 结构组装到 PIDL 中。

创建 SHITEMID 结构

对象的 SHITEMID 结构在其文件夹中唯一标识对象。 事实上,许多 IShellFolder 方法使用的 PIDL 类型只包含对象的 SHITEMID 结构,后跟终止符。 SHITEMID 结构的定义是:

typedef struct _SHITEMID { 
    USHORT cb; 
    BYTE   abID[1]; 
} SHITEMID, * LPSHITEMID;

abID 成员是对象的标识符。 由于 abID 的长度未定义并且可能会有所不同, 因此 cb 成员设置为 SHITEMID 结构的大小(以字节为单位)。

由于 abID 的长度和内容均未标准化,因此可以使用任何要为对象分配 abID 值的方案。 唯一的要求是,同一文件夹中不能有两个具有相同值的对象。 但是,出于性能原因, SHITEMID 结构应与 DWORD 对齐。 换句话说,应构造 abID 值,使 cb 是 4 的整数倍数。

通常, abID 指向扩展定义的结构。 除了对象的 ID 之外,此结构还通常用于保存各种相关信息,例如对象的类型或属性。 然后,扩展的文件夹对象可以从 PIDL 快速提取信息,而不必查询它。

注意

为 PIDL 设计数据结构的最重要方面之一是使结构持久化和可传输。 在 PIDL 的上下文中,这些术语的含义为:

  • 可持久保存。 系统经常将 PIDL 放置在各种类型的长期存储中,例如快捷方式文件。 然后,它可以稍后(可能在系统重新启动后)从存储中恢复这些 PIDL。 已从存储中恢复的 PIDL 必须仍然有效且对扩展有意义。 例如,此要求意味着不应在 PIDL 结构中使用指针或句柄。 当系统稍后从存储中恢复包含此类数据的 PIDL 时,通常毫无意义。
  • 运输。 从一台计算机传输到另一台计算机时,PIDL 必须保持有意义。 例如,PIDL 可以写入快捷方式文件,复制到软盘,然后传输到另一台计算机。 该 PIDL 对于第二台计算机上运行的扩展仍有意义。 例如,若要确保 PIDL 可传输,请显式使用 ANSI 或 Unicode 字符。 避免使用 TCHARLPTSTR 等数据类型。 如果使用这些数据类型,则运行 Unicode 版本的扩展的计算机上创建的 PIDL 将无法被另一台计算机上运行的该扩展的 ANSI 版本读取。

 

以下声明显示了数据结构的简单示例。

typedef struct tagMYPIDLDATA {
  USHORT cb;
  DWORD dwType;
  WCHAR wszDisplayName[40];
} MYPIDLDATA, *LPMYPIDLDATA;

cb 成员设置为 MYPIDLDATA 结构的大小。 此成员使 MYPIDLDATA 本身成为有效的 SHITEMID 结构。 其余成员等效于 SHITEMID 结构的 abID 成员,并保存私有数据。 dwType 成员是扩展定义的值,指示对象的类型。 在此示例中, 文件夹的 dwType 设置为 TRUE ,否则设置为 FALSE 。 例如,此成员允许您快速确定对象是否为文件夹。 wszDisplayName 成员包含对象的显示名称。 由于不会将相同的显示名称分配给同一文件夹中的两个不同对象,因此显示名称还充当对象 ID。 在此示例中, wszDisplayName 设置为 40 个字符,以保证 SHITEMID 结构与 DWORD 对齐。 若要限制 PIDL 的大小,可以改用可变长度字符数组并相应地调整 cb 的值。 在显示字符串中填充足够的“\0”字符,以保持结构的 DWORD 对齐方式。 其他可用于放入结构的成员包括对象的大小、属性或分析名称。

构造 PIDL

为对象定义 SHITEMID 结构后,可以使用它们来构造 PIDL。 可以出于各种目的构造 PIDL,但大多数任务使用两种类型的 PIDL 之一。 最简单的单级 PIDL 标识相对于其父文件夹的对象。 许多 IShellFolder 方法都使用此类型的 PIDL。 单级 PIDL 包含对象的 SHITEMID 结构,后跟终止符。 完全限定的 PIDL 定义从桌面到 对象的命名空间层次结构的路径。 此类型的 PIDL 从桌面开始,并包含路径中每个文件夹的一个 SHITEMID 结构,后跟 对象和终止符。 完全限定的 PIDL 可在整个 Shell 命名空间中唯一标识对象。

构造 PIDL 的最简单方法是直接使用 ITEMIDLIST 结构本身。 创建 ITEMIDLIST 结构,但分配足够的内存来保存所有 SHITEMID 结构。 此结构的地址将指向初始 SHITEMID 结构。 为此初始结构的成员定义值,然后根据需要追加任意数量的 附加 SHITEMID 结构(按适当的顺序)。 以下过程概述了如何创建单级 PIDL。 它包含两个 SHITEMID 结构 - MYPIDLDATA 结构,后跟终止符:

  1. 使用 CoTaskMemAlloc 函数为 PIDL 分配内存。 为专用数据分配足够的内存,并为终止符分配一个 USHORT (两个字节) 。 将结果强制转换为 LPMYPIDLDATA。
  2. 将第一个 MYPIDLDATA 结构的 cb 成员设置为该结构的大小。 在此示例中,将 cb 设置为 sizeof (MYPIDLDATA) 。 如果要使用可变长度结构,则必须计算 cb 的值。
  3. 为私有数据成员分配适当的值。
  4. 计算下一 个 SHITEMID 结构的地址。 将当前 MYPIDLDATA 结构的地址转换为 LPBYTE,并将该值添加到步骤 3 中确定的 cb 值。
  5. 在这种情况下,下一个 SHITEMID 结构是终止符。 将结构的 cb 成员设置为零。

对于较长的 PIDL,请分配足够的内存,并为每个附加 的 SHITEMID 结构重复步骤 3-5。

下面的示例函数采用对象的类型和显示名称,并返回对象的单级 PIDL。 函数假定显示名称(包括其终止 null 字符)不超过为 MYPIDLDATA 结构声明的字符数。 如果该假设被证明是错误的, StringCbCopyW 函数将截断显示名称。 g_pMalloc变量是在其他位置创建的、存储在全局变量中的 IMalloc 指针。

LPITEMIDLIST CreatePIDL(DWORD dwType, LPCWSTR pwszDisplayName)
{
    LPMYPIDLDATA   pidlOut;
    USHORT         uSize;

    pidlOut = NULL;

    //Calculate the size of the MYPIDLDATA structure.
    uSize = sizeof(MYPIDLDATA);

    // Allocate enough memory for the PIDL to hold a MYPIDLDATA structure 
    // plus the terminator
    pidlOut = (LPMYPIDLDATA)m_pMalloc->Alloc(uSize + sizeof(USHORT));

    if(pidlOut)
    {
       //Assign values to the members of the MYPIDLDATA structure
       //that is the PIDL's first SHITEMID structure
       pidlOut->cb = uSize;
       pidlOut->dwType = dwType;
       hr = StringCbCopyW(pidlOut->wszDisplayName, 
                          sizeof(pidlOut->wszDisplayName), pwszDisplayName);
       
       // TODO: Add error handling here to verify the HRESULT returned 
       // by StringCbCopyW.

       //Advance the pointer to the start of the next SHITEMID structure.
       pidlOut = (LPMYPIDLDATA)((LPBYTE)pidlOut + pidlOut->cb);

       //Create the terminating null character by setting cb to 0.
       pidlOut->cb = 0;
    }

    return pidlOut;

对于从桌面到对象的每个对象,完全限定的 PIDL 必须具有 SHITEMID 结构。 当 Shell 调用 IPersistFolder::Initialize 时,扩展会收到根文件夹的完全限定 PIDL。 若要为对象构造完全限定的 PIDL,请获取 Shell 分配给根文件夹的 PIDL,并追加将你从根文件夹带到对象所需的 SHITEMID 结构。

解释 PIDL

当 Shell 或应用程序调用扩展的接口之一来请求有关对象的信息时,它通常会通过 PIDL 来标识该对象。 某些方法(如 IShellFolder::GetUIObjectOf)使用相对于父文件夹且易于解释的 PIDL。 但是,扩展可能还会收到完全限定的 PIDL。 然后,PIDL 管理器必须确定 PIDL 引用的对象。

使对象与完全限定的 PIDL 关联的任务更加复杂,因为 PIDL 中的一个或多个初始 SHITEMID 结构可能属于 Shell 命名空间中扩展外部的对象。 你无法解释这些结构的 abID 成员的含义。 扩展必须执行的是“遍走” SHITEMID 结构列表,直到到达与根文件夹对应的结构。 此后,你将了解如何解释 SHITEMID 结构中的信息。

若要遍进 PIDL,请获取第一 个 cb 值,并将其添加到 PIDL 的地址,以将指针前进到下一 个 SHITEMID 结构的开头。 然后,它将指向该结构的 cb 成员,你可以使用该成员将指针推进到下一个 SHITEMID 结构的开头,依此推。 每次推进指针时,检查 SHITEMID 结构以确定是否已到达扩展命名空间的根。

实现主接口

与所有 COM 对象一样,实现扩展在很大程度上是实现接口集合的问题。 本部分讨论所有扩展都必须实现的三个主要接口。 它们用于初始化,并为 Windows 资源管理器提供有关扩展内容的基本信息。 这些接口以及 文件夹视图是功能扩展所需的全部内容。 但是,为了充分利用 Windows 资源管理器的功能,大多数扩展还实现了一个或多个可选接口。

IPersistFolder 接口

调用 IPersistFolder 接口以初始化新的文件夹对象。 IPersistFolder::Initialize 方法将完全限定的 PIDL 分配给新对象。 存储此 PIDL 供以后使用。 例如,文件夹对象必须使用此 PIDL 为对象的子级构造完全限定的 PIDL。 文件夹对象的创建者还可以调用 IPersist::GetClassID 来请求对象的 CLSID。

通常,文件夹对象由其父文件夹的 IShellFolder::BindToObject 方法创建和初始化。 但是,当用户浏览到你的扩展时,Windows 资源管理器会创建并初始化扩展的根文件夹对象。 根文件夹对象通过 IPersistFolder::Initialize 接收的 PIDL 包含从桌面到根文件夹的路径,你需要为扩展构造完全限定的 PIDL。

IShellFolder 接口

Shell 将扩展视为文件夹对象的分层排序集合。 IShellFolder 接口是任何扩展实现的核心。 它表示文件夹对象,并为 Windows 资源管理器提供显示文件夹内容所需的大量信息。

IShellFolder 通常是除由文件夹对象直接公开的 IPersistFolder 之外的唯一文件夹接口。 虽然 Windows 资源管理器使用各种必需接口和可选接口来获取有关文件夹内容的信息,但它通过 IShellFolder 获取指向这些接口的指针。

Windows 资源管理器通过多种方式获取扩展的根文件夹的 CLSID。 有关详细信息,请参阅 指定命名空间扩展的位置显示命名空间扩展的Self-Contained视图。 然后,Windows 资源管理器使用该 CLSID 创建和初始化根文件夹的实例,并查询 IShellFolder 接口。 扩展将创建一个文件夹对象来表示根文件夹,并返回该对象的 IShellFolder 接口。 然后,扩展与 Windows 资源管理器之间的大部分交互都通过 IShellFolder 进行。 Windows 资源管理器调用 IShellFolder 以:

  • 请求一个对象,该对象可以枚举根文件夹的内容。
  • 获取有关根文件夹内容的各种类型的信息。
  • 请求公开可选接口之一的对象。 然后,可以查询这些接口以获取其他信息,例如图标或快捷菜单。
  • 请求一个文件夹对象,该对象表示根文件夹的子文件夹。

当用户打开根文件夹的子文件夹时,Windows 资源管理器调用 IShellFolder::BindToObject。 扩展创建并初始化一个新的文件夹对象以表示子文件夹,并返回其 IShellFolder 接口。 然后,Windows 资源管理器会调用此接口以获取各种类型的信息,依此类说,直到用户决定在 Shell 命名空间中的其他位置导航或关闭 Windows 资源管理器。

本部分的其余部分简要讨论了更重要的 IShellFolder 方法以及如何实现它们。

EnumObjects

在树视图中显示文件夹的内容之前,Windows 资源管理器必须先通过调用 IShellFolder::EnumObjects 方法来确定文件夹包含的内容。 此方法创建公开 IEnumIDList 接口并返回该接口指针的标准 OLE 枚举对象。 IEnumIDList 接口允许 Windows 资源管理器获取文件夹包含的所有对象的 PIDL。 然后,这些 PIDL 用于获取文件夹包含的对象的相关信息。 有关更多详细信息,请参阅 IEnumIDList 接口

注意

IEnumIDList::Next 方法应仅返回相对于父文件夹的 PIDL。 PIDL 应仅包含对象的 SHITEMID 结构,后跟终止符。

 

CreateViewObject

在显示文件夹的内容之前,Windows 资源管理器会调用此方法来请求指向 IShellView 接口的指针。 Windows 资源管理器使用此接口来管理文件夹视图。 创建文件夹视图对象并返回其 IShellView 接口。

还调用 IShellFolder::CreateViewObject 方法,为文件夹本身请求一个可选接口,例如 IContextMenu。 此方法的实现应创建一个对象,该对象公开请求的接口并返回接口指针。 如果 Windows 资源管理器需要文件夹包含的对象之一的可选接口,它将调用 IShellFolder::GetUIObjectOf

GetUIObjectOf

虽然可通过 IShellFolder 方法获取有关文件夹内容的基本信息,但扩展还可以为 Windows 资源管理器提供各种类型的附加信息。 例如,可以为文件夹或对象的快捷菜单的内容指定图标。 Windows 资源管理器调用 IShellFolder::GetUIObjectOf 方法以尝试检索有关文件夹包含的对象的其他信息。 Windows 资源管理器指定它想要获取信息的对象,以及相关接口的 IID。 然后,folder 对象创建一个对象,该对象公开请求的接口并返回接口指针。

如果扩展允许用户使用拖放或剪贴板传输对象,Windows 资源管理器将调用 IShellFolder::GetUIObjectOf 来请求 IDataObjectIDropTarget 接口。 有关详细信息,请参阅 使用拖放和剪贴板传输 Shell 对象

Windows 资源管理器在需要有关文件夹本身的相同类型信息时调用 IShellFolder::CreateViewObject

BindToObject

当用户尝试打开扩展的子文件夹之一时,Windows 资源管理器会调用 IShellFolder::BindToObject 方法。 如果 riid 设置为 IID_IShellFolder,则应创建并初始化表示子文件夹的文件夹对象,并返回对象的 IShellFolder 接口。

注意

目前,Windows 资源管理器调用此方法仅用于请求 IShellFolder 接口。 但是,不要假设始终如此。 在继续操作之前,应始终检查 riid 的值。

 

GetDisplayNameOf

Windows 资源管理器调用 IShellFolder::GetDisplayNameOf 方法,将文件夹的某个对象的 PIDL 转换为名称。 该 PIDL 必须相对于对象的父文件夹。 换句话说,它必须包含单个非 NULLSHITEMID 结构。 由于有多种可能命名对象的方法,因此 Windows 资源管理器通过在 uFlags 参数中设置一个或多个 SHGDNF 标志来指定名称的类型。 将设置两个值 之一(SHGDN_NORMALSHGDN_INFOLDER),以指定名称是相对于文件夹还是相对于桌面。 可以将其他三个值之一 (SHGDN_FOREDITINGSHGDN_FORADDRESSBARSHGDN_FORPARSING)设置为指定名称的用途。

必须以 STRRET 结构的形式返回名称。 如果未设置 SHGDN_FOREDITINGSHGDN_FORADDRESSBARSHGDN_FORPARSING ,则返回对象的显示名称。 如果设置了 SHGDN_FORPARSING 标志,则 Windows 资源管理器将请求分析名称。 分析名称将传递给 IShellFolder::P arseDisplayName 以获取对象的 PIDL,即使它可能位于命名空间层次结构中的当前文件夹下方的一个或多个级别。 例如,文件系统对象的分析名称是其路径。 可以将文件系统中任何对象的完全限定路径传递给桌面的 IShellFolder::P arseDisplayName 方法,该方法将返回对象的完全限定 PIDL。

虽然分析名称是文本字符串,但它们不一定必须包含显示名称。 应根据在调用 IShellFolder::P arseDisplayName 时最有效工作的名称来分配分析名称。 例如,Shell 的许多虚拟文件夹不属于文件系统,并且没有完全限定的路径。 而是为每个文件夹分配一个 GUID,分析名称采用 ::{GUID} 格式。 无论使用哪种方案,它都应该能够可靠地“往返”。例如,如果调用方将分析名称传递给 IShellFolder::P arseDisplayName 以检索对象的 PIDL,然后将该 PIDL 传递到设置了 SHGDN_FORPARSING 标志的 IShellFolder::GetDisplayNameOf,则调用方应恢复原始分析名称。

GetAttributesOf

Windows 资源管理器调用 IShellFolder::GetAttributesOf 方法来确定文件夹对象包含的一个或多个项的属性。 cidl 的值提供查询中的项数,而 aPidl 指向其 PIDL 列表。

由于测试某些属性可能很耗时,因此 Windows 资源管理器通常通过在 rfgInOut 中设置这些属性的值,将查询限制为可用标志的子集。 方法应仅测试其标志在 rfgInOut 中设置的属性。 保留有效标志设置并清除其余标志。 如果查询中包含多个项,请仅设置应用于所有项的标志。

注意

必须正确设置属性才能正确显示项。 例如,如果项目是包含子文件夹的文件夹,则必须设置 SFGAO_HASSUBFOLDER 标志。 否则,Windows 资源管理器将不会在树视图中项的图标旁边显示 + 。

 

ParseDisplayName

IShellFolder::P arseDisplayName 方法在某种意义上是 IShellFolder::GetDisplayNameOf 的镜像图像。 此方法最常见的用途是将对象的分析名称转换为关联的 PIDL。 分析名称可以引用命名空间层次结构中文件夹下方的任何对象。 返回的 PIDL 相对于公开 方法的文件夹对象,通常不是完全限定的。 换句话说,尽管 PIDL 可以包含多个 SHITEMID 结构,但第一个结构将是对象本身的结构,或者是从文件夹到对象的路径中的第一个子文件夹。 调用方必须将此 PIDL 追加到文件夹的完全限定的 PIDL,以获取对象的完全限定 PIDL。

还可以调用 IShellFolder::P arseDisplayName 来请求对象的属性。 由于确定所有适用的属性可能很耗时,因此调用方将仅设置表示调用方感兴趣的 信息的SFGAO_XXX 标志。 应确定对象中的哪些属性为 true,并清除其余标志。

IEnumIDList 接口

当 Windows 资源管理器需要枚举文件夹包含的对象时,它会调用 IShellFolder::EnumObjects。 文件夹对象必须创建一个枚举对象,该对象公开 IEnumIDList 接口并返回该接口指针。 然后,Windows 资源管理器通常使用 IEnumIDList 枚举文件夹包含的所有对象的 PIDL。

IEnumIDList 是标准的 OLE 枚举接口,以通常的方式实现。 但请记住,返回的 PIDL 必须相对于 文件夹,并且仅包含对象的 SHITEMID 结构和终止符。

实现可选接口

扩展的文件夹对象可以支持许多可选的 Shell 接口。 其中许多功能(例如 IExtractIcon)允许自定义用户查看扩展的方式的各个方面。 其他扩展(如 IDataObject)允许扩展支持拖放等功能。

文件夹对象不会直接公开任何可选接口。 相反,Windows 资源管理器会调用两个 IShellFolder 方法之一来请求接口:

为了提供信息,文件夹对象会创建一个对象,该对象公开请求的接口并返回接口指针。 然后,Windows 资源管理器调用该接口来检索所需的信息。 本部分讨论最常用的可选接口。

IExtractIcon

Windows 资源管理器在显示文件夹内容之前请求 IExtractIcon 接口。 接口允许扩展为文件夹包含的对象指定自定义图标。 否则,将使用标准文件和文件夹图标。 若要提供自定义图标,请创建一个图标提取对象,该对象公开 IExtractIcon 并返回指向该接口的指针。 有关进一步的讨论,请参阅 IExtractIcon 参考文档或 创建图标处理程序

IContextMenu

当用户右键单击对象时,Windows 资源管理器会请求 IContextMenu 接口。 若要为对象提供快捷菜单,请创建菜单处理程序对象并返回其 IContextMenu 接口。

创建菜单处理程序对象的过程与用于创建菜单处理程序 Shell 扩展的过程非常相似。 有关详细信息,请参阅 创建上下文菜单处理程序IContextMenuIContextMenu2IContextMenu3 参考。

IQueryInfo

Windows 资源管理器调用 IQueryInfo 接口以检索信息提示文本字符串。

IDataObject 和 IDropTarget

当对象由 Windows 资源管理器显示时,文件夹对象无法直接知道用户何时尝试剪切、复制或拖动对象。 相反,Windows 资源管理器会请求 IDataObject 接口。 若要允许传输对象,请创建一个数据对象并返回指向其 IDataObject 接口的指针。

同样,用户可能会尝试删除其中一个对象的 Windows 资源管理器表示形式的数据对象,例如图标或地址栏路径。 然后,Windows 资源管理器请求 IDropTarget 接口。 若要允许删除数据对象,请创建一个公开 IDropTarget 接口的对象并返回接口指针。

处理数据传输是编写命名空间扩展的较棘手方面之一。 有关详细讨论,请参阅 使用拖放和剪贴板传输 Shell 对象

使用默认 Shell 文件夹视图实现

使用默认 Shell 文件夹视图对象 (DefView) 的数据源必须实现以下接口:

(可选)它们还可以实现 IPersistFolder3