ATL简介知识

ATL简介知识

一. 什么是ATL

自从1993年Microsoft首次公布了COM技术以后,Windows平台上的开发模式发生了巨大的变化,以COM为基础的一系列软件组件化技术将Windows编程带入了组件化时代。广大的开发人员在为COM带来的软件组件化趋势欢欣鼓舞的同时,对于COM开发技术的难度和烦琐的细节也感到极其的不便。COM编程一度被视为一种高不可攀的技术,令人望而却步。开发人员希望能够有一种方便快捷的COM开发工具,提高开发效率,更好地利用这项技术。

针对这种情况,Microsoft公司在推出COM SDK以后,为简化COM编程,提高开发效率,采取了许多方案,特别是在MFC(Microsoft Foundation Class)中加入了对COM和OLE的支持。但是随着Internet的发展,分布式的组件技术要求COM组件能够在网络上传输,而又尽量节约宝贵的网络带宽资源。采用MFC开发的COM组件由于种种限制不能很好地满足这种需求,因此Microsoft在1995年又推出了一种全新的COM开发工具ATL。

ATL是ActiveX Template Library 的缩写,它是一套C++模板库。使用ATL能够快速地开发出高效、简洁的代码(Effective and Slim code),同时对COM组件的开发提供最大限度的代码自动生成以及可视化支持。为了方便使用,从Microsoft Visual C++ 5.0版本开始,Microsoft把ATL集成到Visual C++开发环境中。1998年9月推出的Visual Studio 6.0 集成了ATL 3.0版本。目前,ATL已经成为Microsoft标准开发工具中的一个重要成员,日益受到C++开发人员的重视。

ATL究竟给开发人员带来了什么样的益处呢?这还要先从ATL产生以前的COM开发方式说起。

在ATL产生以前,开发COM组件的方法主要有两种:一是使用COM SDK直接开发COM组件,另一种方式是通过MFC提供的COM支持来实现。

直接使用COM SDK开发COM组件是最基本也是最灵活的方式。通过使用Microsoft提供的开发包,我们可以直接编写COM程序。但是,这种开发方式的难度和工作量都很大,一方面,要求开发者对于COM的技术原理具有比较深入的了解(虽然对技术本身的深刻理解对使用任何一种工具都是非常有益的,但对于COM这样一整套复杂的技术而言,在短时间内完全掌握是很难的),另一方面,直接使用COM SDK要求开发人员自己去实现COM应用的每一个细节,完成大量的重复性工作。这样做的结果是,不仅降低了工作效率,同时也使开发人员不得不把许多精力投入到与应用需求本身无关的技术细节中。虽然这种开发方式对于某些特殊的应用很有必要,但这种编程方式并不符合组件化程序设计方法所倡导的可重用性,因此,直接采用COM SDK不是一种理想的开发方式。

使用MFC提供的COM支持开发COM应用可以说在使用COM SDK基础上提高了自动化程度,缩短了开发时间。MFC采用面向对象的方式将COM的基本功能封装在若干MFC的C++类中,开发者通过继承这些类得到COM支持功能。为了使派生类方便地获得COM对象的各种特性,MFC中有许多预定义宏,这些宏的功能主要是实现COM接口的定义和对象的注册等通常在COM对象中要用到的功能。开发者可以使用这些宏来定制COM对象的特性。

另外,在MFC中还提供对Automation 和 ActiveX Control的支持,对于这两个方面,Visual C++也提供了相应的AppWizard和ClassWizard支持,这种可视化的工具更加方便了COM应用的开发。

MFC对COM和OLE 的支持确实比手工编写COM程序有了很大的进步。但是MFC对COM的支持是不够完善和彻底的,例如对COM接口定义的IDL语言,MFC并没有任何支持,此外对于近些年来COM和ActiveX技术的新发展MFC也没有提供灵活的支持。这是由MFC设计的基本出发点决定的。MFC被设计成对Windows平台编程开发的面向对象的封装,自然要涉及Windows编程的方方面面,COM作为Windows平台编程开发的一个部分也得到MFC的支持,但是MFC对COM的支持是以其全局目标为出发点的,因此对COM 的支持必然要服从其全局目标。从这个方面而言,MFC对COM的支持不能很好的满足开发者的要求。

随着Internet技术的发展,Microsoft将ActiveX技术作为其网络战略的一个重要组成部分大力推广,然而使用MFC开发的ActiveX Control,代码冗余量大(所谓的“肥代码 Fat Code”),而且必须要依赖于MFC的运行时刻库才能正确地运行。虽然MFC的运行时刻库只有部分功能与COM有关,但是由于MFC的继承实现的本质,ActiveX Control必须背负运行时刻库这个沉重的包袱。如果采用静态连接MFC运行时刻库的方式,这将使ActiveX Control代码过于庞大,在网络上传输时将占据宝贵的网络带宽资源;如果采用动态连接MFC运行时刻库的方式,这将要求浏览器一方必须具备MFC的运行时刻库支持。总之MFC对COM技术的支持在网络应用的环境下也显得很不灵活。

解决上述COM开发方法中的问题正是ATL的基本目标。

首先ATL的基本目标就是使COM应用开发尽可能地自动化,这个基本目标就决定了ATL只面向COM开发提供支持。目标的明确使ATL对COM技术的支持达到淋漓尽致的地步。对COM开发的任何一个环节和过程,ATL都提供支持,并将与COM开发相关的众多工具集成到一个统一的编程环境中。对于COM/ActiveX的各种应用,ATL也都提供了完善的Wizard支持。所有这些都极大地方便了开发者的使用,使开发者能够把注意力集中在与应用本身相关的逻辑上。

其次,ATL因其采用了特定的基本实现技术,摆脱了大量冗余代码,使用ATL开发出来的COM应用的代码简练高效,即所谓的“Slim Code”。ATL在实现上尽可能采用优化技术,甚至在其内部提供了所有C/C++开发的程序所必须具有的C启动代码的替代部分。同时ATL产生的代码在运行时不需要依赖于类似MFC程序所需要的庞大的代码模块,包含在最终模块中的功能是用户认为最基本和最必须的。这些措施使采用ATL开发的COM组件(包括ActiveX Control)可以在网络环境下实现应用的分布式组件结构。

第三,ATL的各个版本对Microsoft的基于COM的各种新的组件技术如MTS、ASP等都有很好的支持,ATL对新技术的反应速度大大快于MFC。ATL已经成为Microsoft支持COM应用开发的主要开发工具,因此COM技术方面的新进展在很短的时间内都会在ATL中得到反映。这使开发者使用ATL进行COM编程可以得到直接使用COM SDK编程同样的灵活性和强大的功能。

本文的目的就是希望在有限的篇幅中能够使读者对ATL的使用和基本原理有一个初步的了解,为广大的COM开发人员更好地使用ATL开发起到抛砖引玉的作用。
二. ATL基本技术

虽然使用ATL开发COM 应用是一件非常简单的事情,但是在ATL简单易用的界面后面却包含着复杂的技术。面对ATL生成的大量代码,我们即使不去深入地了解这些代码的含义也可以开发出COM应用来,但是如果我们要充分地挖掘ATL的潜力,开发出更灵活、强大的COM应用,则必须对ATL使用的基本技术有所了解。研究ATL的实质最好的教材就是由Visual C++提供的ATL源代码。本文这一部分只是对ATL中用到的最基本的技术进行简单的介绍。

简单地说来,ATL中所使用的基本技术包括以下几个方面:

COM技术

C++模板类技术(Template)

C++多继承技术(Multi-Inheritance)

COM技术是理解ATL的基础,使用ATL进行开发要对COM技术的基本概念有最低限度的了解。由于COM是一项非常复杂庞大的技术体系,限于本文的篇幅,这里不再赘述。对于本文中提到的COM基本概念也不做过多的解释,请读者参阅有关的参考书籍。

作为ATL最核心的实现技术的模板是对标准C++语言的扩展,但是在大多数的C++编程环境中,人们很少使用它,这是因为模板的功能虽然很强,但是它内部机制比较复杂,需要比较多的C++知识和经验才能灵活地使用它。在MFC中的CObjectArray等功能类就是由模板来定义的。完全通过模板来定义程序的整体类结构,ATL是迄今为止做得最为成功的。

所谓模板类简单地说是对类的抽象。我们知道C++语言用类定义了构造对象(这里指C++对象而不是COM对象)的方式,对象是类的实例,而模板类定义的是类的构造方式,使用模板类定义实例化的结果产生的是不同的类。因此可以说模板类是“类的类”。

在C++语言中模板类的定义格式如下:


template < class T>

class MyTemp

{

MyTemp<T>( ){ };

~MyTemp<T>( ) { };

int MyFunc( int a) ;

}

………….

Int MyTemp<T>::MyFunc( int a)

{

}

首先使用C++的关键字“template”来声明一个模板类的定义。在关键字后面是用尖括号括起来的类型参数。正是根据这个类型参数,编译器才能在编译过程中将模板类的具体定义转化为一个实际的类的定义,即生成一个新的类。接下来的定义方式与普通的类定义十分相似,只是在类的函数定义中都要带有类型参数的说明。

下面的程序段说明了模板类的用法:


typedef MyTemp<MyClass> myclassfromtemp;

myclassfromtemp m;

int a = m.Myfunc(10);

通常在使用模板类时为了方便起见,使用一个关键字“typedef”为新定义出来的类取一个名字。在上面的程序段中假设“MyClass”是一个由用户定义的类,通过将这个类的名字作为类型参数传递给模板类,我们可以创建一个新的类,这个类的行为将以模板类的定义为基础,例如它具有模板类定义的所有成员函数,同时这个类又是对模板类行为的一种修改,这种修改是通过用户提供的类型参数来实现的。赋予模板类以不同的类型参数,则得到行为框架相似但具体行为不同的一组类的集合。有了新的类的定义以后,我们可以象使用普通类一样来创建一个类的实例,即一个新的对象,并且调用这个对象的成员函数。

模板类是对标准C++语言的最新扩展,虽然它的功能很强大,但是要想使用好模板类需要相当多的关于语言和编程的经验和知识,而且错误地使用模板类又会对程序的结构和运行效率带来大的副作用,因此一般的编程环境和编程书籍对模板类的使用都采取谨慎的态度。而ATL的核心就是由几十个模板类构成的,通过研究ATL的源代码可以使我们对模板类的使用有比较深刻全面的认识。

多继承技术同模板一样,是C++语言中极具争议性的技术。使用多继承技术可以使程序的设计和实现更加灵活,但是,由于多继承的复杂性和自身概念上的一些问题,使多继承在各种面向对象的语言环境中得到的支持都非常有限。例如Small Talk根本就不允许多继承,同样MFC也不支持多继承技术。

多继承最大的问题是所谓的“钻石结构”。例如下面的代码:


class A

{

.....

};

class B : public A

{

.. .

};


class C : public A

{

.....

};


class D : public C,B

{

........

}


由于类D同时从类C和B继承,因此在下面的语句中就会发生歧义:


D* pD = new D;

(A*)pD->Func(...);

由于类D通过类C和类B 分别继承了类A,这里的强制转化就会发生歧义。

ATL使用了C++最新规范中加入的两个运算符号 static_cast、dynamic_cast代替简单的强制转化,从而消除多继承带来的歧义。使用这两个运算符号,我们可以在对象运行过程中获取对象的类型信息。上面的代码可以采用下面的方式修改:


D* pD = new D;

static_cast<A*>(static_cast<B*>(pD))->Func(...);

为什么模板类和多继承技术会成为ATL主要的工具呢?原因在于,采用模板可以在编译过程中快速的生成具有用户定制功能的类,这对于COM这样一个复杂的技术体系在实现效率上得到了很大的提高。通过使用模板类,用户可以把精力集中在自己开发的类的基本逻辑上,在完成了自己的类的设计以后,通过继承不同的类,生成不同的模板类,就可以快速地实现COM的功能,同时又避免了采用单继承结构造成的大量功能冗余。

总之,正是由于在设计实现过程中采用了模板类和多继承技术,才使ATL成为一个小巧灵活的COM开发工具,能够适应开发人员对COM应用开发的各种需要。