的人可能会帮助你。
对本系列文章的总体介绍 WTL 具有两面性,确实是这样的。
它没有 MFC 的界面(GUI)类库那样功能强大,但是能够生成很小的可执行文件。
如果你象我一样使用 MFC 进行界面编程,你会觉得 MFC 提供的界面控件封装使用起来非常舒服,更不用说 MFC 内置的消息处理机制。
当然,如果你也象我一样不希望自己的程序仅仅因为使用了 MFC 的框架就增加几百 K 的大小的话,WTL 就是你的选择。
当然,我们还要克服一些障碍: ATL 样式的模板类初看起来有点怪异 没有类向导的支持,所以要手工处理所有的消息映射。
MSDN 没有正式的文档支持,你需要到处去收集有关的文档,甚至是查看 WTL 的源代码。
买不到参考书籍 没有微软的官方支持 ATL/WTL 的窗口与 MFC 的窗口有很大的不同,你所了解的有关 MFC 的知识并不全部适 用与 WTL。
从另一方面讲,WTL 也有它自身的优势: 不需要学习或掌握复杂的文档/视图框架。
具有 MFC 的基本的界面特色,比如 DDX/DDV 和命令状态的自动更新功能(译者加:比 如菜单的 Check 标记和 Enable 标记)。
增强了一些 MFC 的特性(比如更加易用的分隔窗口)。
可生成比静态链接的 MFC 程序更小的可执行文件(译者加:WTL 的所有源代码都是静态 链接到你的程序中的)。
你可以修正自己使用的 WTL 中的错误(BUG)而不会影响其他的应用程序相比之下,如 果你修正了有 BUG 的 MFC/CRT 动态库就可能会引起其它应用程序的崩溃。
如果你仍然需要使用 MFC,MFC 的窗口和 ATL/WTL 的窗口可以“和平共处”。
(例如我工 作中的一个原型就使用了了 MFC 的 CFrameWnd,并在其内包含了 WTL 的 CSplitterWindow,在 CSplitterWindow 中又使用了 MFC 的 CDialogs -- 我并不是为了炫耀什么,只是修改了 MFC 的代 码使之能够使用 WTL 的分割窗口,它比 MFC 的分割窗口好的多)。
在这一系列文章中,我将首先介绍 ATL 的窗口类,毕竟 WTL 是构建与 ATL 之上的一系列附加类,所以需要很好的了解 ATL 的窗口类。
介绍完 ATL 之后我将介绍 WTL 的特性以并展示它是如何使界面编程变得轻而易举。
对第一章的简单介绍 WTL 是个很酷的工具,在理解这一点之前需要首先介绍 ATL。
WTL 是构建与 ATL 之上的一系列附加类,如果你是个严格使用 MFC 的程序员那么你可能没有机会接触到 ATL 的界面类,所以请容忍我在开始WTL 之前先罗索一些别的东西,绕道来介绍一下 ATL 是很有必要地。
在本文的第一部分,我将给出一点 ATL 的背景知识,包括一些编写 ATL 代码必须知道的基本知识,快速的解释一些令人不知所措的 ATL 模板类和基本的 ATL 窗口类。
ATL 背景知识 ATL 和 WTL 的发展历史 “活动模板库”(Active Template Library)是一个很古怪的名字,不是吗?那些年纪大的人可能还记得它最初被称为“网络组件模板库”,这可能是它更准确的称呼,因为 ATL 的目的就是使编写组件对象和ActiveX 控件更容易一些(ATL 是在微软开发新产品 ActiveX-某某的过程中开发的,那些 ActiveX-某某现在被称为某某.NET)。
由于 ATL 是为了便于编写组件对象而存在的,所以只提供了简单的界面类,相当于MFC 的窗口类(CWnd)和对话框类(CDialog)。
幸运的是这些类非常的灵活,能够在其基础上构建象WTL 这样的附加类。
WTL 现在已经是第二次修正了,最初的版本是 3.1,现在的版本是 7(WTL 的版本号之所以这样选择是为了与 ATL 的版本匹配,所以不存在 1 和 2 这样的版本号)。
WTL 3.1 可以与 VC 6 和 VC 7 一起使用,但是在 VC 7 下需要定义几个预处理标号。
WTL 7 向下兼容 WTL 3.1,并且不作任何修改就可以与 VC 7 一起使用,现在看来没有任何理由还使用 3.1 来进行新的开发工作。
ATL-style 模板 即使你能够毫不费力地阅读 C的模板类代码,仍然有两件事可能会使你有些头晕,以下面这个类的定义为例: class CMyWnd : public CWindowImplltCMyWndgt ... 这样作是合法的,因为 C的语法解释说即使 CMyWnd 类只是被部分定义,类名 CMyWnd 已经被列入递归继承列表,是可以使用的。
将类名作为模板类的参数是因为 ATL 要做另一件诡秘的事情,那就是编译期间的虚函数调用机制。
如果你想要了解它是如何工作地,请看下面的例子: template ltclass Tgt class B1 public: void SayHi T pT static_castltTgtthis // HUH 我将在下面解释 pT-gtPrintClassName protected: void PrintClassName cout ltlt quotThis is B1quot class D1 : public B1ltD1gt // No overridden functions at all class D2 : public B1ltD2gt protected: void PrintClassName cout ltlt quotThis is D2quot main D1 d1 D2 d2 d1.SayHi // prints quotThis is B1quot d2.SayHi // prints quotThis is D2quot 这句代码 static_castltTgtthis 就是窍门所在。
它根据函数调用时的特殊处理将指向 B1 类型的指针 this指派为 D1 或 D2 类型的指针,因为模板代码是在编译其间生成的,所以只要编译器生成正确的继承列表,这样指派就是安全的。
如果你写成:class D3 : public B1ltD2gt就会有麻烦 之所以安全是因为 this 对象只可能是指向 D1 或 D2(在某些情况下)类型的对象,不会是其他的东西。
注意这很像 C的多态性(polymorphism),只是 SayHi方法不是虚函数。
要解释这是如何工作的,首先看对每个 SayHi函数的调用,在第一个函数调用,对象 B1 被指派为 D1,所以代码被解释成: void B1ltD1gt::SayHi D1 pT static_castltD1gtthis pT-gtPrintClassName 由于 D1 没有重载 PrintClassName,所以查看基类 B1,B1 有 PrintClassName,所以 B1 的PrintClassName被调用。
现在看第二个函数调用 SayHi,这一次对象被指派为 D2 类型,SayHi被解释成: void B1ltD2gt::SayHi D2 pT static_castltD2gtthis pT-gtPrintClassName 这一次,D2 含有 PrintClassName方法,所以 D2 的 PrintClassName方法被调用。
这种技术的有利之处在于: 不需要使用指向对象的指针。
节省内存,因为不需要虚函数表。
因为没有虚函数表所以不会发生在运行时调用空指针指向的虚函数。
所有的函数调用在编译时确定(译者加:区别于 C的虚函数机制使用的动态编连),有 利于编译程序对代码的优化。
节省虚函数表在这个例子中看起来无足轻重(每个虚函数只有 4 个字节),但是设想一下如果有 15 个基类,每个类含有 20 个方法,加起来就相当可观了。
ATL 窗口类 好了,关于 ATL 的背景知识已经讲的构多了,到了该正式讲 ATL 的时候了。
ATL 在设计时接口定义和实现是严格区分开的,这在窗口类的设计中是最明显的,这一点类似于 COM,COM 的接口定义和实现是完全分开的(或者可能有多个实现)。
ATL 有一个专门为窗口设计的接口, 这就是 CWindow。
可以做全部的窗口操作, 它实际上就是对 HWND操作的包装类,对几乎所有以 HWND 句柄为第一个参数的窗口 API 的进行了封装,例如:SetWindowText和 DestroyWindow。
CWindow 类有一个公有成员 m_hWnd,使你可以直接对窗口的句柄操作,CWindow还有一个操作符 HWND,你可以将 CWindow 对象传递给以 HWND 为参数的函数,但这与CWnd::GetSafeHwnd(译者加:MFC 的方法)没有任何等同之处。
CWindow 与 MFC 的 CWnd 类有很大的不同,创建一个 CWindow 对象占用很少的资源,因为只有一个数据成员,没有 MFC 窗口中的对象链,MFC 内部维持这一个对象链,此对象链将 HWND 映
上一篇:
手把手教你做UG二次开发
下一篇:
群体性突发事件论文:“边界冲突”:农村群体性事件的县域分析