Shell 命名空间简介

Shell 命名空间 将文件系统和 Shell 管理的其他对象组织到单个树状层次结构中。 从概念上讲,它是更大且更具包容性的文件系统版本。

简介

Shell 的主要职责之一是管理和提供对构成系统的各种对象的访问。 这些对象中数量最多、最熟悉的是驻留在计算机磁盘驱动器上的文件夹和文件。 但是,Shell 还会管理许多非文件系统或 虚拟 对象。 示例包括:

  • 网络打印机
  • 其他联网计算机
  • 控制面板应用程序
  • 回收站

某些虚拟对象根本不涉及物理存储。 例如,打印机对象包含指向网络打印机的链接集合。 其他虚拟对象(如回收站)可能包含存储在磁盘驱动器上的数据,但需要以与普通文件不同的方式进行处理。 例如,虚拟对象可用于表示数据库中存储的数据。 就命名空间而言,数据库中的各种项可以作为单独的对象显示在 Windows 资源管理器中,即使它们都存储在单个磁盘文件中。

虚拟对象甚至可能位于远程计算机上。 例如,为了便于漫游,用户的文档文件可能存储在服务器上。 为了允许用户从多台台式电脑访问其文件,他们当前使用的台式电脑上的“我的文档”文件夹将指向服务器,而不是台式电脑的硬盘。 其路径将包括映射的网络驱动器或 UNC 路径名称。

与文件系统一样,命名空间包括两种基本类型的对象:文件夹和文件。 文件夹对象是树的 节点 ;它们是文件对象和其他文件夹的容器。 文件对象是树的 叶子 ;它们是普通磁盘文件或虚拟对象,例如打印机链接。 不属于文件系统的文件夹有时称为 虚拟文件夹

与文件系统文件夹一样,虚拟文件夹的集合通常因系统而异。 有三类虚拟文件夹:

  • 在所有系统上找到的标准虚拟文件夹,例如回收站。
  • 具有标准名称和功能的可选虚拟文件夹,但并非在所有系统上都存在。
  • 用户安装的非标准文件夹。

与文件系统文件夹不同,用户无法自行创建新的虚拟文件夹。 他们只能安装由非 Microsoft 开发人员创建的。 因此,虚拟文件夹的数量通常比文件系统文件夹的数量少得多。 有关如何实现虚拟文件夹的讨论,请参阅 命名空间扩展

可以在 Windows 资源管理器的资源管理器栏中查看命名空间的结构的可视化表示形式。 例如,Windows 资源管理器的以下屏幕截图显示了一个相对简单的命名空间。

shell 命名空间的视图

命名空间层次结构的最终根是桌面。 根目录正下方是几个虚拟文件夹,例如“我的电脑”和“回收站”。

可以看到,各种磁盘驱动器的文件系统是较大命名空间层次结构的子集。 这些文件系统的根是“我的电脑”文件夹的子文件夹。 “我的计算机”还包括任何映射的网络驱动器的根。 树中的其他节点(例如“我的文档”)是虚拟文件夹。

标识命名空间对象

在使用命名空间对象之前,必须先有一种标识它的方法。 文件系统中的对象可以具有一个名称,例如 MyFile.htm。 由于系统中其他位置可能存在具有该名称的其他文件,因此唯一标识文件或文件夹需要完全限定的路径,例如“C:\MyDocs\MyFile.htm”。 此路径基本上是文件系统根目录 C:\路径中所有文件夹的有序列表,以文件结尾。

在命名空间的上下文中,路径对于标识位于命名空间文件系统部分的对象仍然非常有用。 但是,它们不能用于虚拟对象。 相反,Shell 提供了一种可用于任何命名空间对象的替代标识方法。

项 ID

在文件夹中,每个对象都有一个 项 ID,它与文件或文件夹名称的功能等效。 项 ID 实际上是 SHITEMID 结构:

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

abID 成员是对象的标识符。 abID 的长度未定义,其值由包含 对象的文件夹确定。 由于对于 文件夹分配 abID 值的方式没有标准定义,因此它们仅对关联的文件夹对象有意义。 应用程序应将其视为标识特定文件夹中对象的标记。 由于 abID 的长度各不相同, 因此 cb 成员保留 SHITEMID 结构的大小(以字节为单位)。

由于项 ID 对显示目的没有用,因此包含 对象的文件夹通常会为其分配显示名称。 这是 Windows 资源管理器在显示文件夹内容时使用的名称。 有关如何处理显示名称的详细信息,请参阅 从文件夹中获取信息

项 ID 列表

项目 ID 本身很少使用。 通常,它是项 ID 列表的一部分,其用途与文件系统路径相同。 但是,项 ID 列表不是用于路径的字符串,而是 ITEMIDLIST 结构。 此结构是一个或多个项 ID 的有序序列,以两字节 NULL 结尾。 项 ID 列表中的每个项 ID 对应于一个命名空间对象。 它们的顺序定义命名空间中的路径,就像文件系统路径一样。

下图显示了对应于C:\MyDocs\MyFile.htm的 ITEMIDLIST 结构的示意图。 每个项 ID 的显示名称显示在其上方。 abID 成员的不同宽度是任意的;它们说明了此成员的大小可能有所不同的事实。

pidl 的示意图

PIDL

对于 Shell API,命名空间对象通常通过指向其 ITEMIDLIST 结构的指针或指向项标识符列表 (PIDL) 的指针来标识。 为方便起见,术语 PIDL 通常在本文档中引用结构本身,而不是指向它的指针。

上图中显示的 PIDL 称为 完整 PIDL 或 绝对 PIDL。 完整的 PIDL 从桌面开始,包含路径中所有中间文件夹的项目 ID。 它以对象的项 ID 结尾,后跟终止的双字节 NULL。 完整 PIDL 类似于完全限定的路径,并且唯一标识 Shell 命名空间中的 对象。

不经常使用完整的 PIDL。 许多函数和方法需要 相对 PIDL。 相对 PIDL 的根目录是文件夹,而不是桌面。 与相对路径一样,构成结构的一系列项 ID 定义命名空间中两个对象之间的路径。 尽管它们不唯一标识对象,但它们通常小于完整的 PIDL,并且足以用于许多目的。

最常用的相对 PIDL( 单级 PIDL)相对于对象的父文件夹。 它们仅包含对象的项 ID 和终止 NULL。 多级 PIDL 也用于多种用途。 它们包含两个或多个项 ID,通常通过一系列一个或多个子文件夹定义从父文件夹到对象的路径。 请注意,单级 PIDL 仍可以是完全限定的 PIDL。 具体而言,桌面对象是桌面的子级,因此其完全限定的 PIDL 仅包含一个项 ID。

获取文件夹的 ID 中所述,Shell API 提供了多种检索对象的 PIDL 的方法。 拥有它后,通常只需在调用其他 Shell API 函数和方法时使用它来标识对象。 在此上下文中,PIDL 的内部内容不透明且无关紧要。 出于本讨论的目的,请将 PIDL 视为表示特定命名空间对象的标记,并重点介绍如何将它们用于常见任务。

分配 PIDL

尽管 PIDL 与路径有一些相似之处,但使用它们需要一种略有不同的方法。 主要区别在于如何为其分配和解除分配内存。

与用于路径的字符串一样,必须为 PIDL 分配内存。 如果应用程序创建 PIDL,则必须为 ITEMIDLIST 结构分配足够的内存。 对于此处讨论的大多数情况,Shell 会创建 PIDL 并处理内存分配。 无论分配了何种 PIDL,应用程序通常负责在不再需要 PIDL 时解除分配 PIDL。

使用 CoTaskMemAlloc 函数分配 PIDL,使用 CoTaskMemFree 函数解除分配 PIDL。