在 Windows 系统里,除了传统的存放文件的目录之外,还引入了一些存放特殊对象的文件夹,比如经常使用的“我的电脑”和“网上邻居”等。作为一个开发人员,如果有足够的耐心和毅力的话,还可以编制自己的特殊文件夹,这类程序通常被称之为“外壳名字空间扩展”。如果在 MSDN 和 Internet 上使用“Shell Namespace Extension”关键字搜索,则会找到相当多的资料对该话题进行探讨。要实现一个功能完善的外壳名字空间扩展是一件非常累人的事情,要和大量的接口、结构、常量、外壳函数以及惹人生厌的 PIDL 打交道,更令人痛苦的是,官方文档对很多细节常常一笔带过,语焉不详,导致大量的时间将花费在调试上,因为含有问题的扩展程序将给用户带来非常严重的后果:资源管理器会不停地崩溃。
在系统中,还有一类文件夹,其行为介于传统文件夹和特殊文件夹之间,我们这里不妨称之为半特殊文件夹。它与传统文件夹的相似之处在于文件夹中所存放的都是实实在在的文件,而不是特殊的系统对象;然而在同时,又提供了不同于其他常规文件的特殊操作。这样的文件夹最典型的例子是字体文件夹,另外的两个例子是 Internet Explorer 的历史记录文件夹和临时文件文件夹。
如何建造出一个“半特殊文件夹”,没有找到任何相关的资料。一切都需要摸索着进行。最先应该注意到的一件事情是该类文件夹下面的 desktop.ini,里面通常只有一个节,而且该节里一通常只有一项,项的名字会多少带给我们一些启发:UICLSID。为了得知该 COM 组件究竟实现了些什么东西,不妨先按照常规的特殊文件夹来和该组件进行一下交互。制作一个正常的特殊文件夹的重要步骤是要实现 IShellFolder 接口,但是对字体文件夹的实现组件进行接口查询却并不能得到该接口。事实上实现证明,该组件仅实现了极其有限的几个接口:IShellView、IDropTarget、IPersistFolder,而且从名字也可以有充分的理由认为,第二个接口并非必要条件。实验过程中最奇怪的事情莫过于不能从该组件查询到 IUnknown 接口,不知何故,微软的开发人员好像不应该犯这种低级错误吧。
根据以上知识,制作一个实现了 IShellView、IPersistFolder 接口的组件显然就足够了,当然必要的 desktop.ini 是不可或缺的。可是开始的试验却不能成功。这并非代码的问题,因为执行流程根本没有执行到组件的 DLL 中。desktop.ini 也没有问题,尽管如此,还是把它检查了足有五十遍。最后发现了的原因很有点意思,那就是该物理文件夹必须有只读或者系统属性二者之一,否则系统将不认为该文件夹内的 desktop.ini 需要处理。
基本上就是这些了。不过也还有一件事情很令人头大,那就是在我的代码中,无论怎样处理 IShellView::TranslateAccelerator() 方法,总会导致用键盘访问资源浏览器的菜单不正常。实验过的方法总计有:不处理,总是返回 S_FALSE(这是 MSDN 推荐的返回值);仅处理感兴趣的键盘输入,其余的传递给 IShellBrowser 接口,如果还未被处理则返回 S_FALSE;另外,各种细微的调整无数,可是问题依旧。如果有精力充沛而又对此题目感兴趣的朋友,不妨探索一下解决之道,如果又恰巧解决了,也还请反馈给我。