Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9728071
  • 博文数量: 1227
  • 博客积分: 10026
  • 博客等级: 上将
  • 技术积分: 20273
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-16 12:40
文章分类

全部博文(1227)

文章存档

2010年(1)

2008年(1226)

我的朋友

分类: C/C++

2008-04-23 21:38:44

编写可复用性更好的C 代码
——Band对象和COMToys(一)

编译/

原著:Paul Dilascia

MSJ &

关键字:Bands 对象,Desk Bands,Info/Comm Bands,Explorer Bar,Tool Bands。

本文假设你熟悉C ,COM,IE。

下载本文源代码: (128KB)
(75KB)


第一部分 Band 对象介绍

译者注:
很难将 "Band" 一词与某个中文词语对应起来,所以本文不打算刻意将"Band"这个词语翻译成中文。只要理解Band是Windows外壳扩展(Shell)中的一种应用就行了。如果非要译出来,我比较倾向于把它译成"区带对象"。看一下注册表中的CATID,如果你的机器中安装了Desk Band或者Explorer Bar之类的Band应用程序,那么运行一下CatView.exe程序(这是一个例子程序,可以从VCKBASE在线杂志第十一期的文章《理解COM编程中的“种类”(Category)概念 》中下载)便会看到微软对其的称呼,在“category name”栏中把Desk Bands称为“桌面区”,把Explorer Bars 称为“浏览器区”。还有一个了解Band名称的地方是下面注册表入口处的表项目值:

HKCR\Component Categories\{00021492-0000-0000-C000-000000000046}——桌面区
HKCR\Component Categories\{00021493-0000-0000-C000-000000000046}——Internet Explorer 浏览器区
HKCR\Component Categories\{00021494-0000-0000-C000-000000000046}——Internet Explorer 浏览器通讯带

不管把 Band 叫做什么,关键是要理解 Band 在外壳应用中的角色。

概要介绍:
Band对象有三类:Desk,Info和Comm以及Tools Bands。其中Desk Bands 用于任务栏;Info和Comm--又称浏览栏(Explorer Bar)--用于IE和资源管理器。Tools Bands用于资源管理器或IE的工具栏。本文的例子代码 MyBands.dll 实现了上述前面两种类型的Band对象应用,并介绍了如何在自己的程序中使用 Bands 对象。由于Tools Bands是IE5以后才有的新特性。有关它的实现细节将在另外一篇文章中介绍,关于 Bands 对象的基本概念请参考另外一篇MSDN译文“Windows区对象(Bands)的创建与定制”。
不久以前,有个朋友问我如何在任务栏里添加编辑框控制。他的思路是想获取任务栏的 HWND,然后将编辑框作为子窗口加到任务栏。我当时就断了他的想法:原因是不能再用过去那种龌龊的方法对现在的系统进行编程。如今的操作系统用COM高度集成,正确的方法应该是利用COM所提供的特性或接口与操作系统进行友善的沟通。


      “请把菜单给我好吗?”

      “噢,当然可以,”

      “请拿好菜单。”

      “请现在执行这个命令好吗?”

      “没问题,由IContextMenu来做吧。”

      ......      
完成这些工作只需要外壳扩展中各种各样层出不穷的一个小小接口之一就能搞掂。
但是在这些接口中,我还真没发现一个能将窗口添加到任务栏的现成接口呢!。我当时就告诉那可怜的朋友,他的想法很难实现。后来我发现了band对象和IDeskBand(当时这两个东西刚出来不久,在IE4.0和IE5.0中提供)。立刻觉得它就是我梦寐以求的那种接口。我看到 IDeskBand 接口中只有一个方法。于是决定为什么不自己写一个桌面 band(desk band)来实现我朋友的想法呢?心想不就是用这唯一的一个函数嘛,有什么难的呢?
几个月之后产生了几千行代码(不包括代码笔记和一些节外生枝的附加内容),结果如何呢?到不觉得 band 对象实现起来有多难(实际上也并不难),而是我的工程代码不停地膨胀。写了一个band对象不过瘾;接着又建一个框架。有了框架后还觉得不够;我又创建了一个自己通用的 COM 编程平台。之所以要这么做,主要是想尽量使自己的代码具有更佳的的复用性。众所周知,可复用性乃编程之极致,程序员应该像追求靓女一样不停地追求自己代码的可复用性。在最后完工时,我建立了自己的 BandObj 框架和一些可重用的 COM 代码,它就是将要在后继部分要介绍的 COMToys。而本文我们先讨论 BandObj 的基本内容。

Mybands DLL 的实现逻辑
理解任何系统的最好方式是理解它想要解决的问题(某些系统并不在乎要解决任何问题,这样的系统通常不是好系统)。这就是Mybands DLL的由来。
我最讨厌那种demo例子程序,在一个丑陋的背景上显示一串笨拙的文本,如"Hello [应用程序名字]",然后还整天提起它。我觉得,如果我在编程过程中遇到了麻烦,那么我可能同时也获得了一些有用的东西——或至少是问题细节。所以当我开始写Desk Bands时,要做的第一件事情就是找一个编写它的理由,老实说,把一个自己的一个小窗口放到任务栏里的想法具有挑战性,也很刺激。图一显示的是在任务栏中有一个Web搜索框。

图一 任务栏中的Web搜索框

在这个编辑框中输入要查找的内容,然后按回车键,系统就会启动默认的浏览器并且用你在编辑框的上下文菜单中指定的Web搜索引擎进行查找。你还可以将这个Web搜索框拖到桌面,这时它就变成了一个普通窗口,如图二所示:

图二 任务栏中的Web搜索框变成了一个普通对话框

实现Web搜索框的程序是 Mybands.dll,它是一个DLL。聪明人肯定会问,这个DLL的名字怎么有复数形式?因为它实现了所有三种类型的Band应用。这三种Band对象就是本文前面提到过的:Desk Bands,info/comm和Tools Bands。注意:IE5之后,微软将info/comm类型的Bands统称为Explorer Bars——浏览栏——用于IE或资源管理器--它包括垂直型和水平型,IE以及资源管理器"查看"菜单中"浏览栏"的"历史记录","收藏夹","搜索"(如图三)都属于info类型或者Explorer Bar类型的Bands应用。Tool Bands是IE5新增加的一种Band类型----工具栏Bands。


图三 其它形式的Bands

安装Mybands.dll的方法如下:下载源代码,编译后将dll拷到Windows的系统目录(system或system32),然后将它注册到系统中,方法是:

regsvr32.exe Mybands.dll

注册成功后,在IE或资源管理器的"查看"=〉"工具栏"和"浏览栏"菜单中会出现Bands的菜单项,如图三所示。显示Desk Band需要一点小技巧:必须重新启动资源管理器进程(针对Windows 9x。Windows 2000,Windows XP不需要)。方法是:按组合键"Ctrl Atl Del",删除掉资源管理器进程,重启之后你就可以在任务栏的上下文菜单的"工具栏"中看到Desk Band菜单项了如图四:


图四

使用BandObj编写band对象是很容易的,就以MyBands为例,它由几个模块组成,但只有一个模块是编写band对象的重点,那就是主模块:MyBands.cpp。MyBands由一个叫的App类,它派生于CBandObjDll(BandObj.h),而CBandObjDll又派生于MFC的COleControlModule。它们之间的派生关系为:


    CWinApp

        COleControlModule

    		CBandObjDll

	         	CBandObjDll    

与普通的MFC应用一样,CBandObjDll有一个InitInstance函数:

BOOL CMyBandsDll::InitInstance()

{

   AddBandClass(CLSID_MYINFOBAND,

     RUNTIME_CLASS(CMyInfoBand),

     CATID_InfoBand,

     IDR_INFOBAND);

   AddBandClass(CLSID_MYCOMMBAND, ...);

   AddBandClass(CLSID_MYDESKBAND, ...);

   return CBandObjDll::InitInstance();

}      
它类似于DOC/VIEW,只是DOC/VIEW调用的是AddDocTemplate,而不是AddBandClass。对于每一个Band类,必须提供这个类的ID(GUID),MFC运行时类,种类(category)和资源IDs。种类ID就是一个GUID,它告诉Windows你的类是哪一种Band--是info,comm(Explorer Bar)还是Desk Band。从代码中不难看出,MyBands使用单独的类来处理每一种Band。CMyInfoBand,CMyCommBand,和 CMyDeskBand,它们都派生于CBandObj,并且都使用DECLARE/IMPLEMENT_DYNCREATE,这样MFC就能用其通常的运行时机制和COleObjectFactory来动态创建实例。它们都具有构造函数来负责初始化DESKBANDINFO结构中有关Band的信息及CBandObj::m_dbiDefault。例如,Desk Band有一个默认的宽度(100)及变高。

CMyDeskBand::CMyDeskBand() : CBandObj(CLSID_MYDESKBAND)

{

   m_dbiDefault.ptActual = CPointL(100,0);

   m_dbiDefault.dwModeFlags = DBIMF_VARIABLEHEIGHT;

}     
Explorer Bar 有固定高度30个像素,且没有标题。

CMyCommBand::CMyCommBand() : CBandObj(CLSID_MYCOMMBAND)

 {

   m_strTitle.Empty();

   m_dbiDefault.ptMinSize = CPointL(0,30);

   m_dbiDefault.ptMaxSize = CPointL(-1,30);

 }      
不管你相不相信,MyBands中真正与Band对象有关的东西就这些。剩下的内容无非就是实现Band行为以及一些常规的MFC应用处理。如:CMyDeskBand中OnCreate处理函数的作用是创建编辑框控制,CMyCommBand中WM_PAINT处理函数的作用是绘制有关信息:

void CMyCommBand::OnPaint()

{

   CPaintDC dc(this);

   dc.DrawText("欢迎访问VC知识库!");

}      
Band对象不像框架有最上层菜单,但如果你愿意的话可以为它添加上下文菜单。繁琐的细节都由CBandObj来处理。这时MyBands必须用与Band类相同的资源ID来创建菜单。命令会神奇般地通过所有正常渠道到达MyBands的ON_COMMAND处理函数。如果不是有GUIDs和种类(category)IDs,你很难了解MyBands是一个COM对象。CBandObj隐藏了全部的细节,留下一个自由的空间让你编写自己的Band。这就是我的最终目的所在。(待续)
阅读(340) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~