WTL
(Windows Template Library)
使用教程
前言
在你开始使用 WTL 或者在本文章的讨论区张贴消息之前,我想请你先阅读下面的材料。
你需要开发平台SDK(Platform SDK)。你要使用WTL不能没有它,你可以使用
在线升级安装
开发平台SDK,也可以
下载全部文件后在本地安装。在使用之前要将SDK的包含文件(.h头文
件)和库文件(.Lib文件)路径添加到VC的搜索目录, SDK有现成的工具完成这个工作,这个
工具位于开发平台SDK程序组的“Visual Studio Registration”文件夹里。
你需要安装 WTL。你可以从微软的网站上
下载WTL的 7.0 版,在安装之前可以先查看
“
Introduction to WTL - Part 1”和“Easy installation of WTL”这两篇文章,
了解一下所要安装的文件的信息,虽然现在这些文章有些过时,但还是可以提供很多有用的信
息。有一件我认为不该在本篇文章中提到的事是告诉VC如何搜索WTL的包含文件路径,如果你
用的VC6,用鼠标点击 Tools\Options,转到Directories标签页,在显示路径的列表框
中选择Include Files,然后将WTL的包含文件的存放路径添加到包含文件搜索路径列表中。
你需要了解 MFC。很好地了解 MFC 将有助于你理解后面提到的有关消息映射的宏并能够编
辑那些标有“不要编辑(DO NOT EDIT)”的代码而不会出现问题。
你需要清楚地知道如何使用 Win32 API 编程。如果你是直接从 MFC 开始学习 Windows
编程,没有学过 API 级别的消息处理方式,那很不幸你会在使用 WTL 时遇到麻烦。如果不了
解 Windows 消息中 WPARAM 参数和 LPARAM 参数的意义,应该明白需要读一些这方面的文章
(在 CodeProject 有大量的此类文章)。
你需要知道 C++ 模板的语法,你可以到
VC Forum FAQ 相关的连接寻求答案。
我只是讨论了一些涵盖 VC 6 的特点,不过据我了解所有的程序都可以在 VC 7 上使用。由于
我不使用 VC 7,我无法对那些在 VC 7 中出现的问题提供帮助,不过你还是可以放心的在此
张贴你的问题,因为其他的人可能会帮助你。
对本系列文章的总体介绍:
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 的特性以并展示它是
如何使界面编程变得轻而易举。
第一部分 ATL 中的 GUI 类
对第一章的简单介绍
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 CWindowImpl<CMyWnd>
{
...
};
这样作是合法的,因为 C++的语法解释说即使 CMyWnd 类只是被部分定义,类名 CMyWnd 已经
被列入递归继承列表,是可以使用的。将类名作为模板类的参数是因为 ATL 要做另一件诡秘的
事情,那就是编译期间的虚函数调用机制。
如果你想要了解它是如何工作地,请看下面的例子:
template <class T>
class B1
{
public:
void SayHi()
{
T* pT = static_cast<T*>(this); // HUH?? 我将在下面解释
pT->PrintClassName();
}
protected:
void PrintClassName() { cout << "This is B1"; }
};
class D1 : public B1<D1>
{
// No overridden functions at all
};
class D2 : public B1<D2>
{
protected:
void PrintClassName() { cout << "This is D2"; }
};
main()
{
D1 d1;
D2 d2;
d1.SayHi(); // prints "This is B1"
d2.SayHi(); // prints "This is D2"
}
这句代码 static_cast<T*>(this) 就是窍门所在。它根据函数调用时的特殊处理将指向
B1 类型的指针 this 指派为 D1 或 D2 类型的指针,因为模板代码是在编译其间生成的,所以
只要编译器生成正确的继承列表,这样指派就是安全的。(如果你写成:
class D3 : public B1<D2>
就会有麻烦) 之所以安全是因为 this 对象只可能是指向 D1 或 D2(在某些情况下)类型的对
象,不会是其他的东西。注意这很像 C++的多态性(polymorphism),只是 SayHi()方法不
是虚函数。
要解释这是如何工作的,首先看对每个 SayHi()函数的调用,在第一个函数调用,对象 B1 被
指派为 D1,所以代码被解释成:
void B1<D1>::SayHi()
{
D1* pT = static_cast<D1*>(this);
pT->PrintClassName();
}
由于 D1 没有重载 PrintClassName(),所以查看基类 B1,B1 有 PrintClassName(),所
以 B1 的 PrintClassName()被调用。
现在看第二个函数调用 SayHi(),这一次对象被指派为 D2 类型,SayHi()被解释成:
void B1<D2>::SayHi()
{
评论0