本文内容
Shell命名空间将文件系统和Shell管理的其他对象组织到单个树形层次结构中。从概念上讲,它是更大且更具宽容性的文件系统版本。
简介
Shell的主要职责之一是管理和提供对构成系统的各类对象的访问。那些对象中最诸多、最熟悉的是留驻在计算机c盘驱动器上的文件夹和文件。并且,Shell也会管理许多非文件系统或虚拟对象。示例包括:
个别虚拟对象根本不涉及化学储存。诸如,复印机对象包含指向联网复印机的链接集合。其他虚拟对象(如回收站)可能包含储存在c盘驱动器上的数据,但须要以与普通文件不同的方法进行处理。诸如,虚拟对象可用于表示储存在数据库中的数据。就命名空间而言,数据库中的各类项可以作为单独的对象显示在Windows资源管理器中,虽然它们都储存在单个c盘文件中。
虚拟对象甚至可能坐落远程计算机上。诸如,为了易于漫游,用户的文档文件可能储存在服务器上。为了容许用户从多台台式笔记本访问其文件,她们当前使用的台式笔记本上的“我的文档”文件夹将指向服务器,而不是台式笔记本的硬碟。其路径将包括映射的网路驱动器或UNC路径名称。
与文件系统一样,命名空间包括两种基本类型的对象:文件夹和文件。文件夹对象是树的节点;它们是文件对象和其他文件夹的容器。文件对象是树的叶子;它们是普通c盘文件或虚拟对象,如复印机链接。不属于文件系统的文件夹有时称为虚拟文件夹。
与文件系统文件夹一样,虚拟文件夹的集合一般因系统而异。虚拟文件夹有三类:
与文件系统文件夹不同,用户难以自行创建新的虚拟文件夹。她们只能安装非Microsoft开发人员创建的。因而,虚拟文件夹的数目一般比文件系统文件夹的数目少得多。有关怎样实现虚拟文件夹的讨论,请参阅命名空间扩充。
可以在Windows资源管理器的资源管理器栏中查看命名空间的构造方法的可视化表示方式。诸如,Windows资源管理器的以下屏幕截图显示了相对简单的命名空间。
#5:2:2:6:8:0:7:5:7:a:a:4:8:f:e:d:a:2:b:3:8:2:a:e:4:e:2:5:a:c:d:e#
命名空间层次结构的最终根是桌面。根目录正下方是多个虚拟文件夹,比如“我的笔记本”和“回收站”。
可以看见,各类c盘驱动器的文件系统是较大命名空间层次结构的子集。这种文件系统的根是“我的笔记本”文件夹的子文件夹。“我的计算机”还包括任何映射的网路驱动器的根。树中的其他节点(如“我的文档”)是虚拟文件夹。
标示命名空间对象
在使用命名空间对象之前,必须先有一种标示它的方式。文件系统中的对象可以具有MyFile.htm等名称。因为系统中的其他位置可能存在具有该名称的其他文件,因而惟一标示文件或文件夹须要完全限定的路径,比如“C:\MyDocs\MyFile.htm”。此路径基本上是文件系统根目录C:\路径中所有文件夹的有序列表,以文件结尾。
在命名空间的上下文中,路径对于标示坐落命名空间的文件系统部份中的对象始终十分有用。并且,它们不能用于虚拟对象。相反,Shell提供了可与任何命名空间对象一起使用的取代标示方式。
项ID
在文件夹中,每位对象都有一个项ID,即文件或文件夹名称的功能等效项ID。项ID实际上是SHITEMID结构:
#6:6:6:f:1:5:e:6:3:9:5:7:3:7:2:8:4:0:f:a:a:3:8:8:3:c:6:a:8:4:3:9#
abID成员是对象的标示符。abID的宽度未定义,其值由包含对象的文件夹确定。因为没有标准定义文件夹分配abID值的方法,因而它们仅对关联的文件夹对象有意义。应用程序应将它们视为标示特定文件夹中对象的标记。因为abID的宽度各不相同,因而cb成员保留SHITEMID结构的大小(以字节为单位)。
因为项ID对显示目的没有用,因而包含对象的文件夹一般会为其分配显示名称。这是Windows资源管理器在显示文件夹内容时使用的名称。有关怎样处理显示名称的详尽信息,请参阅从文件夹中获取信息。
项目ID列表
项目ID极少单独使用。一般,它是项ID列表的一部份,其用途与文件系统路径相同。并且,项ID列表不是用于路径的字符串,而是ITEMIDLIST结构。此结构是一个或多个项ID的有序序列,以两字节NULL结尾。项ID列表中的每位项ID对应于一个命名空间对象。其次序定义命名空间中的路径,特别类似于文件系统路径。
右图显示了对应于C:\MyDocs\MyFile.htm的ITEMIDLIST结构的示意图表示方式。每位项ID的显示名称显示在其上方。abID成员的不同长度是任意的;它们说明了此成员的大小可能有所不同的事实。
#6:3:8:6:d:f:b:d:6:6:e:c:1:5:4:5:9:7:b:9:4:5:2:3:1:d:c:b:d:f:7:2#
PIDL
对于ShellAPI,命名空间对象一般通过指向其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中所述,ShellAPI提供了多种检索对象的PIDL的方式。获得它后,一般只需在调用其他ShellAPI函数和技巧时使用它来标示对象。在此上下文中,PIDL的内部内容不透明且无关紧要。出于此讨论的目的,请将PIDL视为表示特定命名空间对象的标记,并重点介绍怎样将它们用于常见任务。
分配PIDL
虽然PIDL与路径有一些相像之处,但使用它们须要一些不同的方式。主要区别在于怎样为它们分配和解除分配显存。
与用于路径的字符串一样,必须为PIDL分配显存。假如应用程序创建PIDL,则必须为ITEMIDLIST结构分配足够的显存。对于此处讨论的大多数情况,Shell会创建PIDL并处理显存分配。无论分配PIDL是哪些,应用程序一般负责在不再须要PIDL时解除分配PIDL。
使用CoTaskMemAlloc函数分配PIDL,使用CoTaskMemFree函数解除分配。