常见资源管理器概念

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

简介

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

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

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

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

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

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

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

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

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

screen shot showing a view of the shell namespace

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

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

标识命名空间对象

在使用命名空间对象之前,必须先确定它。 文件系统中的对象可能有一个名称,例如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 成员的不同宽度是任意的;它们说明了此成员的大小可能有所不同的事实。

a schematic illustration of a 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 函数解除分配。