Shell 名字空间

  翻译自MSDN 2005 -> Win32 和 COM 开发 -> User Interface -> Windows User Experience -> Windows Shell -> Shell Programmer's Guide -> Shell Basics -> The Shell Namespace

     Shell命名空间把文件系统对象和其他由Shell管理的对象组织到单个树状层次结构中。从概念上来说,Shell命名空间是一个更大的包含内容更多的文件系统。

   简介

   管理组成系统的各种对象,并提供对它们的访问方法,是Shell的主要任务之一。Shell对象中数量最大,最为用户所熟知的当然是位于磁盘中的文件和文件夹。然而,Shell还管理着很多非文件系统对象,也就是虚拟对象,比如说:

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

   有些对象是跟物理存储完全不相关的,比如说,包含一些到联网打印机链接的打印机对象;还有一些对象,比如说回收站,可能含有存储在磁盘上的数据,但是需要与普通文件不同的处理方式。例如,可以用一个虚拟对象表示存储在数据库中的数据。从名字空间角度来看,数据库中的各种项目可以以单独对象的形式出现在资源管理器中,哪怕它们实际上是存储在单个磁盘文件中的。

   虚拟对象还可以位于远程计算机中。比如说,为方便漫游,用户的文档可能会存放在服务器中。为使用户能够访问其文件,用户正在使用的PC中的My Documents文件夹将指向服务器,而不是当前PC中的硬盘,其路径将是一个映射的网络驱动器或者是UNC路径名。

   跟文件系统类似,Shell名字空间包含两种基本类型的对象:文件夹和文件。文件夹对象是树的节点,是文件和其他文件夹的容器;文件对象则是树的叶子,它要么是磁盘文件,要么是像打印机这样的虚拟对象。不是文件系统一部分的文件夹有时候也被称作虚拟文件夹。

   与文件系统类似,不同系统中的虚拟文件夹是各不相同的。有三种类型的虚拟文件夹:

  • 标准虚拟文件夹,比如说回收站,在所有系统中都存在。
  • 具有标准名字和功能的可选文件夹,可能不是所有系统中都存在。
  • 由用户安装的非标准文件夹。

   与文件系统不同的是,用户不能自己创建新的虚拟文件夹,而只能安装由非微软开发者创建的虚拟文件夹,所以虚拟文件夹的数量通常比文件系统文件夹要少。对于实现虚拟文件夹的讨论请参考Creating a Shell Namespace Extension

   通过资源管理器的侧边栏可以看到Shell名字空间的结构。比如说,下面的资源管理器截图显示了一个较简单的名字空间。

    

   名字空间的根节点是桌面,紧跟着根节点的是像回收站我的电脑这样的虚拟文件夹。

   各种磁盘驱动器中的文件系统可以看作是大的名字空间层次的子集。这些文件系统的根是我的电脑文件夹的子文件夹。我的电脑还包含映射的网络驱动器的根。树中的其他节点,如我的文档,是虚拟文件夹。

  标识Shell对象

   在使用前,必须有一种标识Shell对象的方法。文件系统中的对象可以有MyFile.htm这样的名字。因为系统中其他地方可能会有同名的文件,所以需要使用像C:/MyDocs/MyFile.htm这样的全限定路径名来唯一标识文件。C:/MyDocs/MyFile.htm这样的全限定路径名是从文件系统根C:/到文件的路径中各个文件夹名字的列表,最后是文件名。

   从名字空间的角度来看,对于标识位于其文件系统部分中的对象,路径还是很有用的。然而,路径不能用于虚拟对象。不同于路径,Shell另外提供了一种用于标识任何对象的方法。

   Item ID

   文件夹中的每个对象都有一个item ID,其功能与文件或者文件夹名字等价。item ID实际上是一个SHITEMID结构: 

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


    abID成员是对象的标识符,其长度是没有定义的,其值也是由包含它的文件夹确定的。因为没有标准定义文件夹该如何分配abID,所以abID仅对对象所在的文件夹有意义。应用程序应该只是简单地把它当做是某个特定文件夹中一个对象的标识符。因为abID成员的长度是不确定的,所以用cb成员来表示SHITEMID结构体的尺寸,单位是字节。

   item ID 对于显示是没有意义的,所以通常文件夹还为对象分配一个显示名。资源管理器在显示文件夹的内容时就使用显示名。关于如何处理显示名,请参考Getting Information From a Folder

   Item ID List

   item ID很少单独使用。通常,item ID是item ID列表的一部分,后者与文件系统路径的功能类似。不同的是,路径使用字符串,而item ID列表使用SHITEMID结构体。item ID列表由一个或者多个item ID顺序排列构成,最后由两个字节的NULL结束。item ID列表中的每个item ID对应一个Shell对象;item ID的顺序定义了名字空间中的一条路径,跟文件系统路径相似。

   下图展示了代表C:/MyDocs/MyFile.htm的item ID列表的结构。各个item ID的显示名在其上方。abID的宽度是任意的,这表示abID这个成员的大小是可变的。

 

PIDL

   从Shell API的角度来看,Shell对象通常由指向ITEMIDLIST结构的指针(pointer to an item identifier list,PIDL)表示。为方便表述,常用PIDL表示结构体本身,而不是指向结构体的指针。

   上图展示的PIDL称作全限定,或者绝对PIDL。全限定PIDL从桌面开始,包含路径中的各个中间文件夹的item ID,最后由对象的item ID和两字节的NULL结束。全限定PIDL与全限定路径名类似,用于唯一标识Shell名字空间中的对象。

    全限定PIDL用得较少。很多函数和方法要求使用相对PIDL。相对PIDL的根是某个文件夹,而不是桌面。与相对路径相似,相对PIDL中的一系列item ID定义了名字空间中两个对象间的一条路径。虽然不能唯一标识一个对象,但相对PIDL较小,在很多情况下也是够用的。

    使用得最多的相对PIDL是单层相对PIDL,也就是直接相对于父文件夹的相对PIDL。单层PIDL仅仅包含对象的item ID和表示结束的NULL。很多情况下也使用多层相对PIDL。多层相对PIDL包含两个或者更多个item ID。单层PIDL也可以是全限定PIDL。比如说,桌面对象是桌面的子对象,所以桌面对象的全限定PIDL仅包含一个itemID。

   Getting a Folder's ID中的讨论可以知道,Shell API提供了很多种获取对象PIDL的方法。一旦获取了PIDL,通常只能在调用Shell API函数时用它来标识对象(而不能用PIDL做其他的什么)。所以,应该仅仅把PIDL看作是代表某个特定的Shell对象的令牌,只关注如何用它完成各种任务。

   PIDL的分配

   虽然PIDL与路径有些相似,但是其使用方法却不同。最主要的不同是如何分配和释放用于PIDL的内存。

   如果应用程序要创建PIDL,必须为其ITEMIDLIST结构体分配足够的内存。然而在多数情况下,Shell API负责创建PIDL和分配内存,而由应用程序释放内存。

   为PIDL分配和释放内存时,必须使用由Shell分配器导出的IMalloc接口。要获得IMalloc接口指针,请调用SHGetMalloc。然后用IMalloc::Alloc方法为PIDL分配内存,用IMalloc::Free方法释放内存。关于如何使用IMalloc,可以参考Getting a Folder's ID


菊子曰 本文用 菊子曰发布
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值