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

2024-01-14 11:38

本文主要是介绍编写可复用性更好的C++代码——Band对象和COMToys(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

编译/赵湘宁

原著:Paul Dilascia 

MSJ  November 1999 & December 1999

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

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

下载本文源代码: MyBands.zip (128KB) 
                TestEditSrch.zip (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。这就是我的最终目的所在。(待续)

Google
<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

这篇关于编写可复用性更好的C++代码——Band对象和COMToys(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/605030

相关文章

Java对象和JSON字符串之间的转换方法(全网最清晰)

《Java对象和JSON字符串之间的转换方法(全网最清晰)》:本文主要介绍如何在Java中使用Jackson库将对象转换为JSON字符串,并提供了一个简单的工具类示例,该工具类支持基本的转换功能,... 目录前言1. 引入 Jackson 依赖2. 创建 jsON 工具类3. 使用示例转换 Java 对象为

javaScript在表单提交时获取表单数据的示例代码

《javaScript在表单提交时获取表单数据的示例代码》本文介绍了五种在JavaScript中获取表单数据的方法:使用FormData对象、手动提取表单数据、使用querySelector获取单个字... 方法 1:使用 FormData 对象FormData 是一个方便的内置对象,用于获取表单中的键值

Vue ElementUI中Upload组件批量上传的实现代码

《VueElementUI中Upload组件批量上传的实现代码》ElementUI中Upload组件批量上传通过获取upload组件的DOM、文件、上传地址和数据,封装uploadFiles方法,使... ElementUI中Upload组件如何批量上传首先就是upload组件 <el-upl

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

Java中对象的创建和销毁过程详析

《Java中对象的创建和销毁过程详析》:本文主要介绍Java中对象的创建和销毁过程,对象的创建过程包括类加载检查、内存分配、初始化零值内存、设置对象头和执行init方法,对象的销毁过程由垃圾回收机... 目录前言对象的创建过程1. 类加载检查2China编程. 分配内存3. 初始化零值4. 设置对象头5. 执行

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没