You are currently browsing the 梦许之地 – WONDERLAND blog archives for November, 2007.

Archive for November, 2007

[翻译整理] Guide to Shell / Namespace Extension Part I

Wednesday, November 28th, 2007

最近由于某种不可抗拒力的需要, 开始啃Windows Shell/Namespace Extension Programming. 因为没有COM 和ATL 基础, 很累人. 在网上找来找去, 关于Shell/Namespace Extension 入门最多的也比较好的就是Code Project 上的几篇软文, Shell Extension 的部分国内有人做了翻译, 做成了CHM, 很不错, 不过原文的教程也已经很明白了, 要写一个Shell 扩展已经成为了可能, 在Visual Studio 的帮助下, 即使没有很深的COM/ATL 知识.

但是我要的是Namespace Extension, 一个比Shell Extension 麻烦多的东西 T_T … Shell Extension 的作者也写了Namespace Extension 的篇文章, 但是明显已经开始跳跃了… 虽然还是Complete Idiot’s Guide to Namespace Extension … 哭…

不过在怎么难受也要继续啃… 加上MSDN 的帮助 — MSDN 上有个Namespace Extension 的例子, RegView, 也挺完整的. 希望可以度过难关啦^^ 这次就做个翻译整理, 权当学习笔记HOHO~~ 边学习边写~~

基础/参考文章地址:

The Complete Idiot’s Guide to Writing Shell Extensions – Index by Michael Dunn [共9个部分]

翻译原文地址:

The Complete Idiot’s Guide to Writing Namespace Extensions – Part I by Michael Dunn [只找到了Part I :( ] 是2001年的文章, 似乎作者已经不再更新了… 但是它的价值依然存在! 另外, 在CodeProject 可以搜索到另外几篇关于Namespace Extension 的很好的文章来填补这篇文章的空白和缺憾. 以下, 褐色文字及代码为原文/翻译文.

1. Introduction [介绍]

从Shell 的角度来看, 计算机的内部组成 — 包括硬盘, 光驱, 网络映射驱动器, 桌面等等 — 被组织在一个树形结构里面, 并且以桌面(Desktop) 为根节点, 我们称之为Shell Namespace. Explorer 通过Namespace Extension 提供了一些方法来插入自定义的对像. 在这篇文章里, 我们会涉及到创建一个基础的, 简单的Namespace Extension 的所有步骤. 我们的扩展(Extension) 会创建一个虚拟文件夹(Virtual Folder) 来列出计算机上的所有驱动器(Drives) , 类似于下面图片中的我的电脑(My Computer).

这篇文章假设读者有C++, ATL 和COM 的有关知识(Know). 熟悉Shell Extension 会有很大帮助.

对于不熟悉ATL, COM, Shell Extension 的可以先看一下作者的上一系列, 关于创建Shell Extension 的文章. 同样文章有点老. 这里提供一个简单的, 在Visual Studio 2005 下创建一个Shell Extension 项目的步骤. 这个步骤同样适用于Namespace Extension.

1.1 新建一个ATL Project. ATL 可以极大地简化我们编写COM 组件的工作… 如图, 选择ATL 项目类型.

Create ATL Project

1.2 创建中选项保持默认就可以了. 结束后出现如下窗口, 无视PS 后缀的项目和Generated Files 系列文件夹.

Project Over View

1.3 右键SimpleShellExt 添加一个新的类, 选择ATL Simple Object (有多种ATL 对象, 以后可以择优选择), 示例一个ContextMenu 的扩展, 选择Simple 就可以了. 如下:

Create ATL Simple Object

1.4 下一步, 出现ATL Simple Object 向导, 选择一个名字(Short Name), 其余的部分会自动填充, 如下:

ATL Simple Object Wizard

1.5 这时候, 可以直接接受默认选项直接Finish, 也可以Next 到Options 窗口选择一些额外的属性. 结束后项目中会多出三个文件, SimpleContextMenuExt.h 和SimpleContextMenuExt.cpp, 还有一个注册表自动注册文件SimpleContextMenuExt.rgs ; 这几个文件都是比较重要的, 在原作者的Shell Extension 教程中指示了如何在这些文件内修改/添加代码来实现一个简单的ContextMenu 扩展.

至此, 项目准备工作结束, 可以开始/继续我们的Shell/Namespace Extension Programming 之路鸟~~

我意识到这会是一篇很长的文章, 因为Namespace Extension 及其复杂, 而且我能找到的最好的文档就是MSDN 内的RegView 示例. 这个实例具有完整的功能, 但是并没有解释Namespace 内事件的内部顺序(Sequence). Dino Esposito 的Visual C++ Windows Shell Programming 分享了另外一些经验, 并且包含了一个基于RegView 的示例WinView. 我从这两个示例中获得灵感, 并且追踪了其中的逻辑流程, 并将在本文中解释.

这篇文章中包含的示例是一个基本的扩展; 它完成了一个很小但是完整的功能. (甚至是一个”简单”的扩展都会需要我们这篇文章中所提到的知识.) 我刻意避开了一些话题 — 比如Namespace 下的子文件夹, 以及和Namespace 的其它部分的交互 — 因为这些会使本文更长, 代码更加庞杂. 我会在今后的文章中介绍这些话题. [很遗憾, 没有了... 要自己另外找...]

2. Structure of Explorer [Explorer 的结构]

这样一个熟悉的结构实际上由几个部分组成, 它们对于一个Namespace Extension 来说很重要. 如下图:

在上图中, 像控制面板(Control Panel), 注册表试图(Registry View) 是虚拟文件夹(Virtual Folder). 他们并不是文件系统(File System) 的一部分, 而是像文件夹一样的UI 元素, 他们由Namespace Extension 提供了一些额外的功能. 一个在右边区域显示自己UI 的扩展(Extension) 被称为 Shell View. 一个扩展也可以填充Explorer 的菜单, 工具栏, 和状态栏, 通过Explorer 提供的一个COM 接口. Explorer 管理着这个树形结构, 用来显示Namespace, 而一个扩展对这个树形结构的控制被限制在现实子文件夹(Subfolder)内.

3. Structure of Namespace Extensions [Namespace 扩展的结构]

当然, 一个Namespace 扩展的内部结构会依赖于你所用的编程语言以及编译器. 但是, 这里有一个重要的通用元素(Common Element) — PIDL. PIDL 全称为 Pointer to an ID List (指向ID 列表的指针), 它是Explorer 用来组织在树型结构中显示的子文件夹和项目的数据结构. 虽然数据的实际结构格式由扩展来定义, 但是有一些规则规定了这些数据在内存中是如何组织的. 这些规则为PIDL 定义了一个通用的/一般性地(Generic) 格式, 因此Explorer 可以从各种扩展中来处理PIDL 而不用担心它们的内部结构.

我知道这很含糊, 但是, 我们需要知道的就是: PIDL 是一个扩展用来存贮对于它有意义的数据的机制. 我会在下文中详细介绍 PIDL, 以及如何创建它们.

扩展的另外一个主要的部分是我们必须要实现的一些COM 接口. 这些必须的接口是:

  • IShellFolder: 为Explorer 和虚拟文件夹的实现代码提供了一个通信的通道.
  • IEnumIDList: 一个COM 迭代器, 可以让Explorer 或者Shell View 遍历一个虚拟文件夹的内容.
  • IShellView: 管理出现在Explorer 右部区域的窗口.

更加复杂的扩展会实现自定义Explorer 的树型结构的结构. 但是我在本文中不会介绍它, 因为文中介绍的这个扩展的目的是尽可能的简单.

4. PIDLs

4.1 What PIDLs are [PIDL 是什么]

Explorer 的Namespace 中每一个项目, 无论是文件, 目录, 控制面板, 或者由一个扩展展示的一个对象, 都可以被它的PIDL 所唯一表示. 一个对象的绝对PIDL 和一个文件的绝对路径相似; 它由该对象自己的PIDL 和它所有的父文件夹的PIDL 连接而成. 举例来说, 系统控制面板元素的绝对PIDL 可以被认为是: [Desktop]\[My Computer]\[Control Panel\[System Applet].

一个相对PIDL 则是该对象自己的PIDL, 相对于它的父文件夹. 这样一个PIDL 只对包含该对象的虚拟文件夹有意义, 因为这个文件夹是唯一能够理解该PIDL 中数据的对象.

本文中的扩展处理相对PIDL, 因为它没有和Namespace 的其他部分发生交互. (这样做需要构造一个绝对PIDL.)

4.2 Structure of a PIDL [PIDL 的结构]

一个PIDL 的结构类似于单链表, 除了没有指针之外. 一个PIDL 包含有一系列的 ITEMIDLIST 结构, 一个挨一个地安置在内存一块连续的区域中. 一个ITEMIDLIST 只有一个成员(Member), 一个SHITEMID 结构:

typedef struct _ITEMIDLIST

{

    SHITEMID  mkid;

} ITEMIDLIST;

SHITEMID 的定义为:

typedef struct _SHITEMID

{

    USHORT cb;       // Size of the ID (including cb itself)

    BYTE   abID[1];  // The item ID (variable length)

} SHITEMID;

成员 cb 记录了整个结构(Struct) 的大小, 功能和单链表中的next 指针相类似. 成员 abID 则是Namespace Extension 存储它自己的数据的地方. 这个成员允许有任意长度; cb 的值指定了它的确切大小. 举例来说, 如果一个扩展存储量12 个字节(byte) 的数据, 则cb 为14 (12+ sizeof(USHOR)). abID 可以存储对于Namespace 来说有意义的任何数据. 但是, 无论如何,一个文件夹下的两个对象都不能有相同的数据, 就好象在同一个目录下不能有两个文件同时有同一个文件名一样.

在PIDL 的结尾由一个cb 字段被设置为0 的SHITEMID 结构指定, 就好象一个链表的最后一个next 指针被设置为NULL 一样.

这里有一个PIDL 的例子, 它只包含了一块数据, 由一个变量pPidl 指向列表的开头.

注意我们可以通过将每个结构的cb 值加到指针上来从一个SHITEMID 结构移动到下一个.

现在, 你可能会问, 如果Explorer 不知道数据的格式, 一个SHITEMID 或者一个PIDL 有什么用. 事实上, Explorer 把PIDL 视作不透明数据类型, 它只负责将它们传送给Namespace. 这很像句柄. 当你有一个, 比如HWND 的时候, 你不用知道在这个窗口内部的数据结构是如何的, 但是你知道你可以通过把它传回给操作系统来对这个窗口做任何事情. PIDL 则相反, Explorer 不知道一个PIDL 内的数据结构, 但是可以通过将其传送给Namespaces 来和他们交互.

4.3 Our Namespace’s PIDL Data

正如上面所提到的, 用来表示Namespace 的文件夹下的项目的数据必须在该文件夹下是唯一的. 幸运的是, 所有的驱动器已经有一个唯一的标志 — 驱动器盘符, 所以我们把该字符存储在abID 内. 我们的PIDL 数据定义为如下的一个PIDLDATA 结构:

struct PIDLDATA

{

    TCHAR chDriveLtr;

};

5. Namespace Extension Interfaces [Namespace 扩展的接口]

5.1 IEnumIDList

IEnumIDList 是一个COM 迭代器(Enumerator) 的实现, 它可以遍历一个PIDL 的集合. 一个COM 迭代器实现了对一个集合的顺序读取, 就像STL 集合的迭代器(Iterator) 一样. ATL 为我们提供了实现了该迭代器的类, 所以我们所需要做的只是提供数据的集合以及高速ATL 如何去存取PIDL.

IEnumIDList 在以下两种情况下被使用:

  1. Shell View 需要遍历一个文件夹的内容以便显示它们.
  2. Explorer 需要遍历一个文件夹的子文件夹以便填充树形结构.

因为我们的扩展不包含子文件夹, 因此我们只需要考虑第一种情况.

5.2 IShellFolder, IPersistFolder

IShellFolder 是Explorer 用来初始化一个扩展以及和它交流的接口. Explorer 会在创建View 窗口的时候调用IShellFolder 的方法. IShellFolder 也有遍历一个扩展的虚拟文件夹的内容的方法, 以及为了排序而比较两个项目的方法.

IPersistFolder 有一个方法, Initialize(), 一个扩展可以调用它来完成任何初始化任务.

5.3 IShellView, IOleCommandTarget

IShellView 是Explorer 用来通知一个扩展一些UI 有关的事件的接口. IShellView 有一些方法来告诉扩展去创建/销毁一个View 窗口, 刷新显示的内容, 等等. IOleCommandTarget 被Explorer 用来向View 发送命令(Commands), 比如用户按下F5 时的刷新命令.

5.4 IShellBrowser

IShellBrowser 是Explorer 暴露的一个接口, 用来让扩展填充Explorer 窗口. IShellBrowser 有一些方法来修改菜单, 工具栏, 状态栏等等, 也可以发送一个通用的消息给Explorer 的控件.

理论完毕, 第二部分将会是具体实现部分.

[... To Be Continued]

赚钱和花钱

Sunday, November 25th, 2007

本来兴致勃勃地, 把父母的话当耳边风, 一心想要买个数码单反去世界各地旅行, 摄影, 尤其是埃及; 自以为按照现在的收入水平, 这样的活动还是能够消费得起的, 大不了小小地分几期付款. 可是最近办浦发银行信用卡被拒, 被直接打击了. 各种美好愿望的第一步被无情地破坏了… 虽然再一次提交了申请, 但是我想, 即使卡办下来了, 我也不会去买40D — 这个对现在的我来说这么奢侈的一个东西了, 也不会想要去揣着一张所谓的CITI Bank 的信用卡四处旅行了, 虽然这些东西都是我的梦想, 但是, 我想现在的我是不会去实践它们了. Sorry, My Dreams…

前晚还梦见自己端着单反, 透过小小的取景器去拍摄各种自己喜欢的景色; 早上醒来以后无比郁闷, 又不想买相机, 就跑去徐家汇看游戏机去了, 又开始幻想买个次世代的游戏机… 为什么就这么想买东西呢… 废…

在上大学前, 一直幻想自己在大学里奋发图强, 出类拔萃, 结果在一次次堕落之后, 在毕业后无比后悔&& 感慨, 发誓&& 幻想在工作以后要静下心来好好努力, 不能再浪费青春, 结果, 还是和在大学一样… 心总是静不下来, 明明周围环境很好, 能够好好利用, 好好学点东西, 好好地利用一下这宝贵的青春, 干一番事情的.

在我还没有赚多少钱的时候, 我满脑子的却是如何花钱, 而不是赚钱… 在上海, 在这样一个年龄, 有这样的想法真他妈的恐怖… 我终于开始意识到了. 周围好多人都在努力工作, 努力创业, 努力在自己的天地里加油奔跑着, 我却停留在原地, 幻想要享受一下这难得的”青春好时光”. 真F**K EGG…

现在这个年龄要是就开始”享乐主义”, 开始”注重面子”, 那真太危险了… 被银行拒应该是有原因的吧, 小样儿, 年纪还小, 凭什么让银行相信你, 在还没有创造足够价值的时候就想要消费, 要享受,省省吧…

伟大的BO说了句话, 让我很受震动… “我不想要那种平平稳稳的生活, 我一定要干出点事业…” 噢, 我不是正好相反的想法嘛, S**T… 我表面上是个急性子, 骨子里却是个慢性子, 慢, 慢, 好像很稳当, 但事实却是, 这样的人生毫无激情, 等老了以后回忆起来, 我还剩下什么?

我们还小啊… 真的还小… 在社会这样鱼龙混杂的地方, 在上海这个大都市, 我们不仅小, 还渺小… 在花钱之前, 一定要先去赚钱, 赚足够的钱, 让自己花钱花到不care, 这才是年轻人该干的事情. 败家子很有可能就是所谓的小白领. SIGH…

发了次疯, 不知道效果能持续多久, 老爸说过, 我是三分钟热度, 老师说过, 我是慢热型, 那如何才能让自己燃烧起青春呢… 那种火热的青春.

明天周一, 在修正了恶心的Memory Leak 之后 , 终于要开始接触到一个全新的领域了, 两个星期, 看自己能不能搞定. SHELL EXTENSION & COM. 那个什么, 很出名的, 哦, Aza Aza Fighting, 据说是某韩剧的台词, 唉… 最近看了不少韩国电影, 养养眼, 补偿一下空虚的心灵. 接下来, 当然是继续工作啦. 虽然我还不会疯狂, 但是, 至少, 我要愤怒.

做自己的DJ

Thursday, November 22nd, 2007

一直以DJ自居, 却连擦盘机都没有摸过, 唯一一次亲眼见到DJ也还是在印度那会儿=.= 实在是… SIGH…

如今, 终于被我找到这么一个利器, 可以用来混音 T_T 而且有着非常Professional 的职业DJ 的界面 ^^

最近心情郁闷的不行, 这个东西的出现总算解救了我… 哪怕是一点点, 呵呵.

好吧, 下面隆重登场的是: 当当当当… Atomix Virtual DJ! 来个正面特写先 :D

Virtual DJ

是不是很有气势, 哈哈~~ 冰山一角啊!

图片上是我试着用BSB 的Treat Me Right 来混一点简单的效果, 结果惨不忍睹… 惨不忍听… 唉… 完全没有DJ 的样子, 哈哈, 哈哈, 哈哈 (尴尬地笑, 挠头…)

不过再怎么样, 这个软件可真是真家伙, 可以外接DJ 控制器和外输出到音频设备的专业级软件, 买的话$299 哦 -_|||

忽然想起我那个DJ 游戏控制器… 上面有转盘, 可以拿来用貌似… 改天放上完整攻略, 哈哈, 敬请期待 ^^

冲动不?想不想拿鼠标去转那个盘子? 嘿嘿~~ 做自己的DJ 吧! 混出自己的好味道!

Team Building

Wednesday, November 21st, 2007

最近天气又开始有些回暖, Team Building 也终于在这个阳光灿烂的日子里成功进行.

在经历了满头大汗的集体跳绳和烟雾弥漫的烧烤以后, 我们回归了^^

1. 经历死亡的恐怖

可能夸张了点… 不过坐在”大风车”的最外端, 每一次的旋转都是绝对的心跳. 对于一个自转+公转的系统来说, 我已经不指望它有任何一刻让人喘息的机会了=.= 我木有相机, 哭… 而且我在上面也木有办法照 -_||| 从youtube上找了个视频哈哈. 大家看看, 下次有机会去, 绝对不要错过!

这个玩意, 一定要坐在最外面才能体会到极端的”绝望”. 想喊的话千万不要憋住, 也憋不住哈哈. 我就喊了, 不停地喊. 不过这次很好, 我全程睁眼嘿嘿, 不然太浪费了…

2. 瞬间的刺激…

这个说的是过山车~~ 虽然长度比锦江乐园要长得多, 而且也有三个环, 但是还是感觉一下子就过去了. 不过瘾啊… 尤其在经历了刚才的风车之后, 更觉得这个不够尽兴呵呵, 简直就是小儿科啊哈哈. 这个木有图=.=

3. 漂移的快感

没有想到卡丁车的第一次就给了这个小小的地方, SIGH… 完全没有车的感觉, 踏板居然是两条铁丝绕成的… 速度也一般, 场地太小, 赛道太短… T_T 总之不过瘾就是老…

话说回来, 不过瘾归不过瘾, 好久没有碰车子的身体遇上这样的地方还是稍稍放纵了一下. 不自觉地不断切内线, 虽然过弯时候速度不快, 而且方向盘很”敏感”, 但是在>90度的弯的时候还是不自觉的收了收油门, 结果, 车子嘎一下就慢了 -_||| 完全没有缓冲… 找不到感觉啊哈哈, 要是有极品飞车的操控感就好了嘿嘿.

最后刹车的时候, 屁股甩出去了, 传说中的速差和转向过度终于出现了 @_@ 最后的一刻! 也是该换人的时候了…

4. 碰碰碰碰, 可以死命打方向盘的一个东西

碰碰车… 让我觉得最舒服的就是可以单手狂转方向盘… 看上去悠哉悠哉地, 然后突然撞向某人… 貌似很厉害的样子, 注意, 是貌似^^ 很久没有玩的东西, 让我找回了一点童年呵呵~~

其实玩的4个节目都比较回归, 只是时间太短, 结束后还要回公司做Build… 然后一开Outlook 就发现了Build Break, Memory Leak… 傻眼了, 傻B了… 明天有得忙了… 怀念小时候的说~~

Father and Son

Tuesday, November 20th, 2007

“You will be different, sometimes you’ll feel like an outcast, but you’ll never be alone. You will make my strength your own. You will see my life through your eyes, as your life will be seen through mine. The son becomes the father, and the father becomes the son.”

That’s the talk between the father and the son. No, from a father to a son. Sometimes, you can save them, but you can’t just be one of them.

“Will we see you… around?”

“I’m always around.”

When you feel burndens’ down, you do the right thing.

Some exciting news come from colleagues, from the US side. It seems to be the very begining, that a son becomes the father, and sees all the future through his own eyes.

到了晚上10点才有了点胃口, 于是跑出去给自己买了4个烧烤, 一路上回来也吃得津津有味.

现在晚上的风已经很刺骨了, 即使是穿着羊毛衫, 还是会不自觉地瑟瑟发抖.

在家门口吃烧烤的样子应该很狼狈, 狼吞虎咽, 嘴边和手指上全是油, 呵呵, 除了左手.

从下午开始就浑, 忽然觉得这个寄托 — 红的很刺眼.

再尝试一次吧, 再努力一次吧, I can see the future, I should see, and I must be able to see it.