ATL开发指南的第三章的讲述的重点有四个:
1.ATL如何提供对组件宿主的支持。
2.ATL如何提供对IUnknown接口实现的支持。
3.ATL如何提供对类工厂的支持。
4.ATL如何提供对组件自注册的支持。
3.1 ATL 的基本特征
描述:ATL提供了实现基于COM组件内核的支持.下面是ATL所提供的一些功能
1.AppWizard,它负责创建起始的ATL工程
2.Object Wizard(对象向导),它为基本的COM组件创建代码
3.对低级别的COM功能的内置式支持,如IUnknown,类工厂和自注册
(self-registration)功能
4.ATL支持Microsoft的接口定义语言(Interface Definition Language,IDL),它提供
了对自定义的Vtable接口的调度支持,以及通过类型库进行自描述的功能
5.ATL支持IDispatch(自动化)和双向接口(dual-interface)
6.ATL可以支持开发效率更高的ActiveX控件
7.ATL提供对基本的视窗功能的支持
3.2 ATL 和 MFC
描述:ATL的目标是为了简化小规模的,基于COM组件的创建.MFC则基于Windows应用程序的开发速度,它通常带有大量的GUI.两者的相似之处是对OLE和ActiveX的支持
3.3 ATL 框架结构概述
描述:ATL是一个C++的类库或框架,它处理基于COM程序开发中的很多琐碎的例行工作,如,COM组件需要一个DLL或EXE宿主,而组件也需要一个类工厂.
1)ATL是一个基于模板的框架,它将ATL的实现作为你组件实现里的一部分.因此,你只需要在程序里包含头文件,即可获得ATL内建的功能.
2)ATL的设计目标是为了建立小型的,独立的组件.ATL提供了几个选项处理可执行文件变大的问题.如:
// stdafx.h
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
#include <atlcom.h>
....
// stdafx.cpp
#include "stdafx.h"
// include ATL's implementation code
#include <atlimpl.cpp>
// Yourimplementation.cpp
#include "stdafx.h"
stdafx文件包含了工程类型的基本要求,所以需要把它包含在你的实现文件里,通过ATLIMPL.CPP大部分ATL的实现都成为工程的一个显示部分,它的代码也变成你的可执行文件的一部分
ATL 的实现文件
文件名称
|
说明
|
ATLBASE.H
|
ATL工程的基本包含文件
|
ATLCOM.H
|
所有的ATL工程都必须包含ATLCOM.H,因为该文件提供了ATL的大部分基本行为
|
ATLIMPL.CPP
|
在ATLBASE.H和ATLCOM.H里声明的类和方法的实现代码
|
ATLCTL.H,ATLCTL.CPP
|
ATL对ActiveX控件所提供的支持,若使用ATL的控件支持,应包含它们
|
ATLWIN.H,ATLWIN.CPP
|
ATL对视窗和对话框的支持
|
STATREG.H,STATREG.CPP
|
ATL的注册组件的实现文件
|
ATLIFace.IDL,ATLIFACE.H
|
ATL的注册器组件的支持文件,头文件里包含了输出,该输出是通过MIDL编译器运行IDL的结果
|
3)ATL实现一些基本的API是在一个名为ATL.DLL的模块里进行的.它提供ATL类的辅助函数.
4)如果定义了ATL_DLL_符号变量,工程将依赖于ATL.DLL文件.若没有,ATLIMPL.CPP文件将把实现作为模块的一部分包含进来
ATL在它的CComModule类里封装了一个组件的宿主支持.ATL对开发者掩盖了这两种宿主类型(dll或exe)之间的大多数差别.
在下面为详细讲述.
1)CComClassFactory提供了对基本的类工厂的支持
2)CComClassFactory2对获得许可的类工厂提供支持
3)CComClassFactorySingleton为单元素类工厂提供支持
COM的功能项
|
ATL的支持类
|
ActiveX控件
|
CComControl,IOleControlImpl,IOleObjectImpl 等都支持控件开发
|
自动化(Automation)
|
IDispatchImpl处理自动化和双向接口
|
COM的数据类型
|
CComVariant
|
接口指针的管理
|
CComPtr 和 CComQIPtr
|
错误处理
|
ISupportErrorInfoImpl 和CComObject
|
连接点(Connection points)
|
IConnectionPointContainerImpl 和 IConnectionPointImpl
|
异步属性下载
|
CBindStatusCallback
|
自注册(self-registration)
|
ATL的注册对象(Register object,Iregistrar)提供自注册功能
|
视窗和对话框
|
CWindow,CWindowImpl,CDialogImpl,CMessageMap
|
Apartment: 组件的实例可以存在于它们自身的单元(Apartment)线程。
Free: 组件支持自由线程管理模型里(Free Threading Model)。换句话说,它必须和其它线程一起位于多线程单元(Multithread Apartment 或 MTA)里。
Both: 它指定组件既可以支持单元模型,也可以支持自由线程模型。
1)每一个COM对象都必须支持IUnknown接口和其他公开其特定功能的接口
2)每一个COM对象也必须提供一个类工厂,从而客户应用程序才可以创建它
3)COM对象应该提供自注册功能
1) 每一个将成为COM对象的ATL类都必须从CComObjectRootEx类里派生出来.
2)CComObjectRootEx间接地为组件提供了引用计数和QueryInterface支持
3) CComObjectRootEx 从CComObjectRootBase继承,CComObjectRootBase对组件里的基本集合提供支持,而CComObjectRootEx对非集合的IUnknown方法提供支持。
1)ATL通过CComObjectRootEx的内部和外部方法来管理引用的计数,CComObject中的类则处理对IUnknown方法实现
2)生成CMath类实例IMath *pIMath = new CComObject<CMath>
3)实现math组件所必须的继承图
1.CComObjectRoot提供InternalAddRef,InternalRelease,InternalQueryInterface
2.CComCoClass 提供了对类工厂的支持
3.IMath,IAdvancedMath 提供了抽象的接口类
4.以上这些组合在一起生成了CMath类,ATL更深一步,为了创建实例,它使用CMath作为CComObject的模板参数,使CComObject从CMath中派生出来,为组件的IUnknown接口提供实现。
CComObject类直接调用了由CComObjectRootEx 实现的内部方法(如InternalAddRef),所以不能支持集合。
在ATL里,你可以使用几个类似于CComObject 的类来创建真正的、可实例化的类。
类名称
|
说明
|
CComObject
|
在大多数典型的COM组件里使用。该对象不支持集合,也不能处理引用计数,而通常的对象则可以支持集合及处理引用计数。当引用计数器减小到零时,它就把自己删除掉。
|
CComObjectNoLock
|
类似于CComObject,不过该对象的生存期不会影响组件宿主文件的锁定计数,ATL在它的宿主类工厂的实现里使用了该类,这是因为宿主类工厂的生存期不应该影响宿主的生存期
|
CComAggObject
|
它仅仅支持集合。IUnKnown的实现通过外部组件来实现。
|
CComContainedObject
|
因为它把所有的调用都委托给外部对象(或父级对象),所以它类似于一个集合对象。然而,当该类被包含到你的实现里时(换句话说,也就是当你不进行显式的集合操作时),你可以使用该类(个人认为可以理解为“包容”)。
|
CComPolyObject
|
它支持集合或标准实现。该类基本上是一个占位实现。
|
CComObjectStack
|
该实现完全不支持引用计数。它是结合堆栈所创建的COM对象一起使用的。堆栈所创建的COM对象的生存期有一定限制,这一点不难理解。
|
CComObjectGlobal
|
CComObjectGlobal的生存期和组件宿主文件的生存期相同。换句话说,它完全类似于一个全局的C++对象。它的生存期是宿主的全局锁定计数器决定的。
|
CComObjectCached
|
一旦创建了该类的对象,它就会存储在对象的缓存里。ATL使用它来实现一个组件的类工厂。
|
CComTearOffObject
|
Tear-off对象提供了一种只在需要时创建类的机制。
|
注册器(Registrar)是一个简单的、数据驱动的机制,它使用宿主文件组件的信息来刷新注册表。它定义了IRegistrar接口,Registrar 组件的实现由STATREG.H 和 STAREG.CPP提供。
在组件的头文件中使用DECLARE_REGISTRY_RESOURCEID()宏来注册组件。DECLARE_REGISTRY_RESOURCEID宏使用包含RGS文件的资源ID做为参数,使用RGS的内容进行注册。