VC++ ATL 学习总结
2017-04-04 10:09
162 查看
ATL (一种微软程序库)
ATL,Active Template Library活动模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。通过活动模板库,可以建立COM组件,然后通过ASP页面中的脚本对COM对象进行调用。这种COM组件可以包含属性页、对话框等控件。
中文名 ATL 类 型 一种微软程序库 支 持 C++语言 年 份 1993年
目录
1 什么是ATL
2 ATL基本技术
3 ATL基本使用
4 应用举例
什么是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组件的开发提供最大限度的代码自动生成以及可视化支持。为了方便使用,从MicrosoftVisual 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>
classMyTemp
{
MyTemp<T>(){};
~MyTemp<T>(){};
intMyFunc(inta);
}
………….
IntMyTemp<T>::MyFunc(inta)
{
}
首先使用C++的关键字“template”来声明一个模板类的定义。在关键字后面是用尖括号括起来的类型参数。正是根据这个类型参数,
编译器才能在编译过程中将模板类的具体定义转化为一个实际的类的定义,即生成一个新的类。接下来的定义方式与普通的类定义十分
相似,只是在类的函数定义中都要带有类型参数的说明。
下面的程序段说明了模板类的用法:
typedefMyTemp<MyClass>myclassfromtemp;
myclassfromtempm;
inta=m.Myfunc⑽;
通常在使用模板类时为了方便起见,使用一个关键字“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继承,因此在下面的语句中就会发生歧义:
1
2
D*pD=newD;
(A*)pD->Func(...);
由于类D通过类C和类B 分别继承了类A,这里的强制转化就会发生歧义。
ATL使用了C++最新规范中加入的两个运算符号static_cast、dynamic_cast代替简单的强制转化,从而消除多继承带来的歧义。使用这
两个运算符号,我们可以在对象运行过程中获取对象的类型信息。上面的代码可以采用下面的方式修改:
1
2
D*pD=newD;
static_cast<A*>(static_cast<B*>(pD))->Func(...);
为什么模板类和多继承技术会成为ATL主要的工具呢?原因在于,采用模板可以在编译过程中快速的生成具有用户定制功能的类,这对
于COM这样一个复杂的技术体系在实现效率上得到了很大的提高。通过使用模板类,用户可以把精力集中在自己开发的类的基本逻辑
上,在完成了自己的类的设计以后,通过继承不同的模板类,生成不同的类,就可以快速地实现COM的功能,同时又避免了采用单继
承结构造成的大量功能冗余。
总之,正是由于在设计实现过程中采用了模板类和多继承技术,才使ATL成为一个小巧灵活的COM开发工具,能够适应开发人员对
COM应用开发的各种需要。
ATL基本使用
这一部分将重点介绍ATL的基本使用过程。由于ATL已经被集成在Microsoft Visulal Studio的Visual C++开发环境中,因此要使用ATL
必须先安装Visual C++。在下面的讨论中有关COM的基本知识请参阅有关的文档,这里不再详细说明。
使用ATL开发一个COM应用基本可以分为以下几个步骤:
创建一个新的ATL工程,并对工程的选项进行适当的配置。
向新创建的工程添加新的ATL类,并对该类进行一些初始配置工作。
根据COM应用的基本要求向新的ATL类加入新的接口定义,并实现相应的接口成员函数。
编译连接工程,注册COM应用。
下面将根据这些步骤依次介绍ATL的基本使用过程(给出的是Visual Studio 6.0的使用):
1. 创建工程
首先启动Visual C++集成开发环境,选择“File”菜单下的“New...”命令,在“New”对话框中选择“Project”页。
选择“ATL COM AppWizard”项,这是创建ATL工程的AppWizard向导入口。然后在“Project name”编辑框中输入工程的名字,单
击“OK”按钮,进入AppWizard对话框。
在AppWizard对话框中主要的设置选项有:
COM服务程序的类型:
-动态连接库(Dynamic Linking Library) 最终产生一个动态连接库(DLL)形式的COM服务程序;
-应用程序(Executable application)最终产生一个可执行程序类型(EXE)的COM服务程序;
- NT服务(NT Service):产生一个以NT服务方式运行的COM服务程序。
允许嵌入Proxy/Stub代码。由Microsoft提供的MIDL编译IDL文件以后,将产生用于对象调度(Marshaling)的Proxy/Stub的代码。
传统地,这部分代码与COM服务程序的代码是分离的,但是由于新的COM标准支持多线程环境下的COM对象服务,因此在动态连接
库的COM服务程序中也要有Proxy/Stub的支持。为了支持在网络上的传输,ATL允许用户选择将Proxy/Stub的代码包括在生成的DLL
代码中。这个选项在EXE和NT服务类型的COM应用条件下不可选。
允许支持MFC。由于ATL对除COM以外的基本的Windows编程方面的支持极为有限,同时许多程序员对MFC又非常熟悉,因此在ATL
的工程设置中允许在ATL工程内部支持使用MFC,即可以使用MFC定义的类。这在一方面来看是非常方便的,特别是对于习惯于使用
MFC的开发人员来说,能够使用MFC提供的各种功能强大的类的支持,而不必直接使用Windows SDK。从另一个方面来看,在ATL工
程中使用MFC同时就丧失了ATL代码轻量级的特点。
支持MTS。MTS是Microsoft Transaction Server的缩写,它是Microsoft在COM技术方面的一个新的分支,这里不作详细说明。
完成上面的设置以后,可以选择FINISH完成工程的设置,ATL将创建相应的工程。
2. 加入ATL类
完成工程的创建和设置以后,下一步就是向工程中加入一个新的ATL类。Visual Studio集成环境提供了向导工具“ATL Object Wizard
”用于加入一个新的ATL类。操作过程并不复杂,只是一组对话框操作而已。
首先通过集成环境的“Insert”菜单下的“New ATL Object…”命令进入“ATL Object Wizard”对话框。
这个对话框即为创建ATL对象的向导起始界面。对话框的左边部分说明了待创建对象的基本类型,这里主要有以下的几种类型:
对象(Object)基本的COM对象类型;
控制(Control)ActiveX Control类型的ATL对象;
其他(Miscellaneous)辅助功能,如对话框的生成等;
数据访问(Data Access)数据访问,支持MTS等。
右边部分说明了每种类型的详细内容,对于一般的COM服务程序,使用对象表中的简单对象(Simple Object)就可以了。
选定待创建对象的基本类型以后,单击“Next>;”按钮进入下一步,进入对象属性设置对话框,如图4和图5所示。
对象属性设置分为两个过程:先是对象名字标识的设定,然后是对对象的基本属性进行设置。首先是对象的名字标识设置。
在对象标识编辑框中输入待创建对象的名字,ATL对象向导将同步地根据用户输入的对象标识设定该对象的C++标识和COM标识。对象
的C++标识包括对象的类名,cpp文件名和头文件名。COM标识包括对象在类型库中的CoClass段和实现的主接口的名字,同时还有在
系统注册表中的类型名以及ProgID。
对象名字标识设置完成以后,选择对象属性页(Attribute)进入对象的属性设置页面。
对象的属性设置是ATL对象创建过程中最复杂的部分,包括以下几个主要部分:
对象的线程模型(Thread Model)
对象的线程模型是COM对象在多线程环境下被访问时对访问方式的控制,缺省情况下在ATL中采用的是套间模型Apartment,由系统通
过消息队列方式提供并发控制。
对象的接口模型(Interface)
COM对象的接口可以是双接口(Dual Interface)。双接口不同于普通接口(Custom Interface) 之处在于双接口是从Automation基
本接口IDispatch继承的,而普通接口是从IUnknown接口直接继承来的。缺省的接口模型是双接口。
对象的聚合模型(Aggregate)
COM规范不允许对象的实现继承,但是可以通过聚合方式重用其它的COM对象。ATL对象属性设置中的聚合模型可以指定待创建的
COM对象是否支持聚合模型。缺省的选项是支持对象的聚合。
对象对错误处理的支持(Support ISupportErrorInfo)
选取这个选项可以在对象的运行过程中支持错误处理。缺省情况下这个选项不被选中。
对象对连接点的支持(Support Connection Points)
连接点是COM对象的事件机制。选中这个选项可以使待创建的COM对象具有发出事件的能力。缺省情况下该选项不被选中。
对象对自由线程调度的支持(Free Thread Marshaller,简称FTM)
对象的自由线程调度是对象在处于自由线程模型状态下,为了简化对象的访问过程而采用的一种优化策略。缺省情况下该选项不被选中
。
对于上述的任何一个选项的详细描述都涉及到COM技术一些核心的内容,并且都已超出本文的范围,因此本文只对ATL给出的缺省选项
加以说明,对这些内容感兴趣的读者可以参考Microsoft提供的文档。
完成了上面的设置以后,就可以按“OK”按钮完成对象的创建过程。下一步就是向所生成的ATL类的接口中加入成员函数的定义,以及
接口成员函数的实现过程。
3. 加入接口定义,实现接口函数
加入了ATL类定义之后,我们可以打开Visual C++集成环境下项目管理器(Workspace)中的Class View来检查生成的类定义的情况。
我们可以看到一个新的类已经生成,同时,还生成了相应的接口定义。ATL Object Wizard为我们生成了类定义的.h 和.cpp文件,此外
还有用于接口定义的IDL文件。有了这些文件以后,我们就可以为接口加入成员函数,完成类的定义。
首先在Class View中选中相应的接口,显示为接口IATLTest,单击鼠标右键打开菜单,如图7。此弹出式菜单定义了为接口加入属性和
方法的操作。选取其中的“Add Method...”项,可以为接口加入方法成员;选取“Add Property...”则可以为接口加入新的属性成员
。
加入属性和方法的对话框可以参看图8和图9。如果我们要在接口中加入一个方法,则选取“Add Method...”菜单命令。假设方法名为
ABC,方法的返回类型为COM规定的HRESULT类型。我们也可以定义非HRESULT返回类型的函数,但是这需要手工修改接口定义的
IDL文件。我们定义ABC方法的一个参数为a,类型为整数型。完成了方法的定义以后,单击“OK”按钮则把此方法加入到接口中。
属性的加入过程是类似的。属性加入对话框要求指定属性的类型、名字以及属性的访问方式。在属性和方法的编辑对话框中都有一个“
Attributes”按钮,在给出了一个属性或方法的基本定义之后,单击此按钮,可以对属性和方法的一些高级特性进行设置。
方法成员加入以后,我们可以通过Class View来检查ATL为我们所做的工作。首先我们看到ATL在接口的定义中加入了该方法的定义;
同时在对应的ATL类定义中,也加入了一个相应的方法的定义;在类对应的.cpp文件中,加入了此方法的实现框架。此后,我们只要在
这个函数框架中加入该方法的代码逻辑,一个接口函数的定义和实现就基本完成了。依照这种方式,我们可以完成整个COM对象的定
义和实现。
完成以上的步骤之后,我们就可以编译连接应用了。
4. 编译连接应用、注册COM服务程序
对ATL工程的编译连接过程包括下面的几个步骤:
使用MIDL编译工程的IDL文件,形成接口定义的头文件和用于调度(Marshalling)的代码;
编译工程的.cpp文件形成目标文件;
连接目标文件,形成应用模块;
注册COM服务程序。
关于工程编译连接的其它部分同Visual C++中MFC工程的编译连接过程相似,这里只重点介绍一下COM服务程序的注册过程。
在ATL中,COM服务程序的注册是在工程编译连接的最后阶段,由ATL辅助完成的。在手工的COM编程中,服务程序的注册是比较麻
烦的工作。在ATL中,系统通过读取在建立工程过程中形成的注册脚本文件来完成注册工作。注册脚本(Register Script 简称RGS)是
ATL提供的文本方式的注册辅助文件。下面是注册脚本文件的一个实例。
HKCR - 表示注册表中COM对象的注册项,是HKEY_CLASS_ROOT的缩写
{
AuthTest.ActiveXObject.1 = s 'ActiveXObject Class'
{
CLSID = s ''
} - 对象的ProgID
AuthTest.ActiveXObject = s 'ActiveXObject Class'
{
CLSID = s ''
} -对象的与版本无关的ProgID
NoRemove CLSID -对象CLSID注册项
{
ForceRemove = s 'ActiveXObject Class'
{
ProgID = s 'AuthTest.ActiveXObject.1'
VersionIndependentProgID = s 'AuthTest.ActiveXObject'
InprocServer32 = s '%MODULE% -服务器类型,表示DLL服务器
{
val ThreadingModel = s 'both' -线程模型,这里是BOTH型
}
}
}
}
RGS文件包含注册COM服务程序的各项内容,通常我们不必修改此RGS文件,必要时我们也可以手工修改RGS文件来定制模块的注册过
程。
应用举例
上面介绍了使用ATL创建一个COM服务程序的基本过程。在介绍过程中,我们实际上已经生成了一个COM服务程序的基本框架,只是
没有填写实际的内容。在下面部分,我们实际开发一个十分简单的COM服务程序,并且为它编写一段客户代码进行测试,使大家对使
用ATL开发COM服务程序的过程有一个全面整体的了解。
我们要开发的服务程序的功能很简单,它只实现一个接口,这个接口名字是ISimpleInterface,接口只有一个成员函数,叫做Welcome
。这个函数的功能只是输出一个“Hello World!”的字符串。
按照上一部分介绍的创建COM服务程序的步骤,我们进行如下的操作:
1.打开Visual C++集成开发环境;
2.创建一个称为SimpleTest的ATL工程;
3.在这个工程中插入新的对象,对象的名字是SimpleInterface;
4.设置接口ISimpleInterface的有关属性,使它成为一个双接口;
5.在对象的接口ISimpleInterface中加入方法Welcome;
6.打开ATL加入的Welcome方法的框架,可以看到如下的代码段:
STDMETHODIMPCActiveXObject::get_TestProp(long*pVal)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
//TODO:Addyourimplementationcodehere
returnS_OK;
}
7.将程序框架中的注释部分替换为下面的代码:
1
::MessageBox(NULL,_T(”HelloWorld!”),_T(”Welcome”),MB_OK);
Welcome方法被调用时将弹出一个消息框。
8.编译连接工程。
上面的步骤完成以后,我们就有了一个简单的COM服务程序,而且已经被注册到当前系统中。
下面我们要完成一个简单的COM客户程序。一个COM客户程序简单地说是使用COM组件对象的程序。客户程序调用COM对象的基本
流程是:
创建COM对象的实例。这可以通过调用Windows系统的API函数CoCreateInstance来完成。
通过接口调用函数。
调用IUnknown::Release释放COM对象实例
我们的客户程序是使用MFC编写的一个基于对话框的简单应用程序。具体的过程如下:
1.打开Visual C++集成开发环境;
创建一个称为SimpleClient的基于对话框的MFC工程;
在对话框中加入一个按钮,名字为TEST;
在SimpleClientDlg.cpp文件中加入如下的代码:
⑴ 在cpp文件 #include “simpleclientdlg.h”之后加入下面的代码:
#include"d:\simpletest\simpletest.h"
#include"d:\simpletest\simpletest_i.c"
加入的头文件是在编译COM服务程序过程中自动生成的,其中包含接口本身的定义、接口IID的定义和COM对象的CLSID的定义。包含
该头文件可以使客户程序能够使用COM服务程序。
⑵ 在按钮TEST的消息控制函数中加入如下的代码:
CoInitialize(0);
HRESULThr;
ISimpleInterface*pIntf=NULL;
hr=CoCreateInstance(CLSID_SimpleInterface,NULL,CLSCTX_SERVER,
IID_ISimpleInterface,(void**)&pIntf);
if(SUCCEEDED(hr))
{
pIntf->Welcome();
pIntf->Release();
}
CoUninitialize();
上面的代码首先通过系统API CoCreateInstance创建COM对象,得到接口的指针,然后调用接口成员函数Welcome,最后通过
IUnknown::Release()函数释放COM对象实例。
编译连接客户程序
最后,我们可以测试客户程序是否正常运行。启动客户程序,当单击“TEST”按钮时我们可以看到弹出一个消息框,这正是我们的
COM服务程序提供的功能。
========
ATL与COM之间的关系、ATL的特点与基本使用方法
http://blog.csdn.net/chenyujing1234/article/details/7753930ATL,Active Template Library活动模板库
是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。通过活动模板库,可以建立COM组件,然后通过ASP页面
中的脚本对COM对象进行调用。这种COM组件可以包含属性页、对话框等等控件。
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++开发人员的重视。
1、 ATL究竟给开发人员带来了什么样的益处呢?这还要先从ATL产生以前的COM开发方式说起。
1、1 在ATL产生以前,开发COM组件的方法主要有两种:
(1)一是使用COM SDK直接开发COM组件;
直接使用COM SDK开发COM组件是最基本也是最灵活的方式。通过使用Microsoft提供的开发包,我们可以直接编写COM程序。但是
,这种开发方式的难度和工作量都很大,一方面,要求开发者对于COM的技术原理具有比较深入的了解(虽然对技术本身的深刻理解
对使用任何一种工具都是非常有益的,但对于COM这样一整套复杂的技术而言,在短时间内完全掌握是很难的);
另一方面,直接使用COM SDK要求开发人员自己去实现COM应用的每一个细节,完成大量的重复性工作。这样做的结果是,不仅降低
了工作效率,同时也使开发人员不得不把许多精力投入到与应用需求本身无关的技术细节中。虽然这种开发方式对于某些特殊的应用很
有必要,但这种编程方式并不符合组件化程序设计方法所倡导的可重用性,因此,直接采用COM SDK不是一种理想的开发方式。
(2)另一种方式是通过MFC提供的COM支持来实现。
使用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的支持不能很好的满足开发者的要求。
1、2 随着Internet技术的发展,Microsoft将ActiveX技术作为其网络战略的一个重要组成部分大力推广
然而使用MFC开发的ActiveX Control,代码冗余量大(所谓的“肥代码 Fat Code”),而且必须要依赖于MFC的运行时刻库才能正
确地运行。虽然MFC的运行时刻库只有部分功能与COM有关,但是由于MFC的继承实现的本质,ActiveX Control必须背负运行时刻库
这个沉重的包袱。
(1)如果采用静态连接MFC运行时刻库的方式,这将使ActiveX Control代码过于庞大,在网络上传输时将占据宝贵的网络带宽资源;
(2)如果采用动态连接MFC运行时刻库的方式,这将要求浏览器一方必须具备MFC的运行时刻库支持。总之MFC对COM技术的支持
在网络应用的环境下也显得很不灵活。
2、解决上述COM开发方法中的问题正是ATL的基本目标。
(1)首先ATL的基本目标就是使COM应用开发尽可能地自动化,这个基本目标就决定了ATL只面向COM开发提供支持。目标的明确使
ATL对COM技术的支持达到淋漓尽致的地步。对COM开发的任何一个环节和过程,ATL都提供支持,并将与COM开发相关的众多工具
集成到一个统一的编程环境中。对于COM/ActiveX的各种应用,ATL也都提供了完善的Wizard支持。所有这些都极大地方便了开发者
的使用,使开发者能够把注意力集中在与应用本身相关的逻辑上。
(2)其次,ATL因其采用了特定的基本实现技术,摆脱了大量冗余代码,使用ATL开发出来的COM应用的代码简练高效,即所谓
的“Slim Code”。ATL在实现上尽可能采用优化技术,甚至在其内部提供了所有C/C++开发的程序所必须具有的C启动代码的替代部
分。
同时ATL产生的代码在运行时不需要依赖于类似MFC程序所需要的庞大的代码模块,包含在最终模块中的功能是用户认为最基本和最必
须的。这些措施使采用ATL开发的COM组件(包括ActiveX Control)可以在网络环境下实现应用的分布式组件结构。
(3)第三,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)
1、COM技术是理解ATL的基础
使用ATL进行开发要对COM技术的基本概念有最低限度的了解。由于COM是一项非常复杂庞大的技术体系,限于本文的篇幅,这里不
再赘述。对于本文中提到的COM基本概念也不做过多的解释,请读者参阅有关的参考书籍。 eg: <<COM技术内幕.pdf>>
2、作为ATL最核心的实现技术的模板是对标准C++语言的扩展
但是在大多数的C++编程环境中,人们很少使用它,这是因为模板的功能虽然很强,但是它内部机制比较复杂,需要比较多的C++知识
和经验才能灵活地使用它。在MFC中的CObjectArray等功能类就是由模板来定义的。完全通过模板来定义程序的整体类结构,ATL是迄
今为止做得最为成功的。
所谓模板类简单地说是对类的抽象。我们知道C++语言用类定义了构造对象(这里指C++对象而不是COM对象)的方式,对象是类的实
例,而模板类定义的是类的构造方式,使用模板类定义实例化的结果产生的是不同的类。因此可以说模板类是“类的类”。
在C++语言中模板类的定义格式如下:
注意:<和>是左右尖括号,可能无法正常显示。
template < class T> class MyTemp
{
MyTemp( ){ };
~MyTemp( ) { };
int MyFunc( int a) ;
}
………….
Int MyTemp::MyFunc( int a) { }
首先使用C++的关键字“template”来声明一个模板类的定义。在关键字后面是用尖括号括起来的类型参数。正是根据这个类型参数,
编译器才能在编译过程中将模板类的具体定义转化为一个实际的类的定义,即生成一个新的类。接下来的定义方式与普通的类定义十分
相似,只是在类的函数定义中都要带有类型参数的说明。
下面的程序段说明了模板类的用法:
typedef MyTemp myclassfromtemp;
myclassfromtemp m;
int a = m.Myfunc(10);
通常在使用模板类时为了方便起见,使用一个关键字“typedef”为新定义出来的类取一个名字。
在上面的程序段中假设“MyClass”是一个由用户定义的类,通过将这个类的名字作为类型参数传递给模板类,我们可以创建一个新的
类,这个类的行为将以模板类的定义为基础,例如它具有模板类定义的所有成员函数,同时这个类又是对模板类行为的一种修改,这种
修改是通过用户提供的类型参数来实现的。
赋予模板类以不同的类型参数,则得到行为框架相似但具体行为不同的一组类的集合。有了新的类的定义以后,我们可以象使用普通类
一样来创建一个类的实例,即一个新的对象,并且调用这个对象的成员函数。
模板类是对标准C++语言的最新扩展,虽然它的功能很强大,但是要想使用好模板类需要相当多的关于语言和编程的经验和知识,而且
错误地使用模板类又会对程序的结构和运行效率带来大的副作用,因此一般的编程环境和编程书籍对模板类的使用都采取谨慎的态度。
而ATL的核心就是由几十个模板类构成的,通过研究ATL的源代码可以使我们对模板类的使用有比较深刻全面的认识。
3、多继承技术同模板一样,是C++语言中极具争议性的技术。
使用多继承技术可以使程序的设计和实现更加灵活,但是,由于多继承的复杂性和自身概念上的一些问题,使多继承在各种面向对象的
语言环境中得到的支持都非常有限。例如Small Talk根本就不允许多继承,同样MFC也不支持多继承技术。
多继承最大的问题是所谓的“钻石结构”。
例如下面的代码:
[cpp] view plain copy
class A { ..... };
class B : public A { .. . };
class C : public A { ..... };
class D : public C,B { ........ }
由于类D同时从类C和B继承,因此在下面的语句中就会发生歧义:
[cpp] view plain copy
D* pD = new D;
A*)pD->Func(...);
由于类D通过类C和类B 分别继承了类A,这里的强制转化就会发生歧义。
ATL使用了C++最新规范中加入的两个运算符号 static_cast、dynamic_cast代替简单的强制转化,从而消除多继承带来的歧义。使用这
两个运算符号,我们可以在对象运行过程中获取对象的类型信息。上面的代码可以采用下面的方式修改:
[cpp] view plain copy
D* pD = new D;
static_cast(static_cast(pD))->Func(...);
为什么模板类和多继承技术会成为ATL主要的工具呢?原因在于,采用模板可以在编译过程中快速的生成具有用户定制功能的类,这对
于COM这样一个复杂的技术体系在实现效率上得到了很大的提高。通过使用模板类,用户可以把精力集中在自己开发的类的基本逻辑
上,在完成了自己的类的设计以后,通过继承不同的类,生成不同的模板类,就可以快速地实现COM的功能,同时又避免了采用单继
承结构造成的大量功能冗余。
总之,正是由于在设计实现过程中采用了模板类和多继承技术,才使ATL成为一个小巧灵活的COM开发工具,能够适应开发人员对
COM应用开发的各种需要。
三. ATL基本使用
这一部分将重点介绍ATL的基本使用过程。由于ATL已经被集成在Microsoft Visulal Studio的Visual C++开发环境中,因此要使用ATL
必须先安装Visual C++。在下面的讨论中有关COM的基本知识请参阅有关的文档,这里不再详细说明。给出的图是在Microsoft
Windows 98平台下Visual Studio 6.0的使用示意图。
使用ATL开发一个COM应用基本可以分为以下几个步骤:
(1)创建一个新的ATL工程,并对工程的选项进行适当的配置。
(2)向新创建的工程添加新的ATL类,并对该类进行一些初始配置工作。
(3)根据COM应用的基本要求向新的ATL类加入新的接口定义,并实现相应的接口成员函数。
(4)编译连接工程,注册COM应用。
下面将根据这些步骤依次介绍ATL的基本使用过程。
1、创建工程
首先启动Visual C++集成开发环境,选择“File”菜单下的“New...”命令,在“New”对话框中选择“Project”页。
选择“ATL COM AppWizard”项,这是创建ATL工程的AppWizard向导入口。然后在“Project name”编辑框中输入工程的名字,单
击“OK”按钮,进入AppWizard对话框。在AppWizard对话框中主要的设置选项有:
(1、1)COM服务程序的类型:
- 动态连接库(Dynamic Linking Library) 最终产生一个动态连接库(DLL)形式的COM服务程序;
- 应用程序(Executable application)最终产生一个可执行程序类型(EXE)的COM服务程序;
- NT服务(NT Service):产生一个以NT服务方式运行的COM服务程序。
(1、2)允许嵌入Proxy/Stub代码。由Microsoft提供的MIDL编译IDL文件以后,将产生用于对象调度(Marshaling)的Proxy/Stub
的代码。传统地,这部分代码与COM服务程序的代码是分离的,但是由于新的COM标准支持多线程环境下的COM对象服务,因此在
动态连接库的COM服务程序中也要有Proxy/Stub的支持。为了支持在网络上的传输,ATL允许用户选择将Proxy/Stub的代码包括在生
成的DLL代码中。这个选项在EXE和NT服务类型的COM应用条件下不可选。
(1、3)允许支持MFC。由于ATL对除COM以外的基本的Windows编程方面的支持极为有限,同时许多程序员对MFC又非常熟悉,因
此在ATL的工程设置中允许在ATL工程内部支持使用MFC,即可以使用MFC定义的类。这在一方面来看是非常方便的,特别是对于习惯
于使用MFC的开发人员来说,能够使用MFC提供的各种功能强大的类的支持,而不必直接使用Windows SDK。从另一个方面来看,在
ATL工程中使用MFC同时就丧失了ATL代码轻量级的特点。
(4)支持MTS。MTS是Microsoft Transaction Server的缩写,它是Microsoft在COM技术方面的一个新的分支,这里不作详细说明
。
完成上面的设置以后,可以选择FINISH完成工程的设置,ATL将创建相应的工程。
2、加入ATL类
完成工程的创建和设置以后,下一步就是向工程中加入一个新的ATL类。
Visual Studio集成环境提供了向导工具“ATL Object Wizard”用于加入一个新的ATL类。操作过程并不复杂,只是一组对话框操作而
已。
首先通过集成环境的“Insert”菜单下的“New ATL Object…”命令进入“ATL Object Wizard”对话框。
这个对话框即为创建ATL对象的向导起始界面。对话框的左边部分说明了待创建对象的基本类型,这里主要有以下的几种类型:
对象(Object)基本的COM对象类型;
控制(Control)ActiveX Control类型的ATL对象;
其他(Miscellaneous)辅助功能,如对话框的生成等;
数据访问(Data Access)数据访问,支持MTS等。
右边部分说明了每种类型的详细内容,对于一般的COM服务程序,使用对象表中的简单对象(Simple Object)就可以了。
选定待创建对象的基本类型以后,单击“Next>”按钮进入下一步,进入对象属性设置对话框,如图4和图5所示。 对象属性设置分
为两个过程:先是对象名字标识的设定,然后是对对象的基本属性进行设置。首先是对象的名字标识设置。 在对象标识编辑框中输
入待创建对象的名字,ATL对象向导将同步地根据用户输入的对象标识设定该对象的C++标识和COM标识。对象的C++标识包括对象
的类名,cpp文件名和头文件名。COM标识包括对象在类型库中的CoClass段和实现的主接口的名字,同时还有在系统注册表中的类型
名以及ProgID。 对象名字标识设置完成以后,选择对象属性页(Attribute)进入对象的属性设置页面。 对象的属性设置是ATL
对象创建过程中最复杂的部分,包括以下几个主要部分: 对象的线程模型(Thread Model) 对象的线程模型是COM对象在多
线程环境下被访问时对访问方式的控制,缺省情况下在ATL中采用的是套间模型Apartment,由系统通过消息队列方式提供并发控制。
对象的接口模型(Interface) COM对象的接口可以是双接口(Dual Interface)。双接口不同于普通接口(Custom Interface) 之
处在于双接口是从Automation基本接口IDispatch继承的,而普通接口是从IUnknown接口直接继承来的。缺省的接口模型是双接口。
对象的聚合模型(Aggregate) COM规范不允许对象的实现继承,但是可以通过聚合方式重用其它的COM对象。ATL对象属
性设置中的聚合模型可以指定待创建的COM对象是否支持聚合模型。缺省的选项是支持对象的聚合。 对象对错误处理的支持
(Support ISupportErrorInfo) 选取这个选项可以在对象的运行过程中支持错误处理。缺省情况下这个选项不被选中。 对象对
连接点的支持(Support Connection Points) 连接点是COM对象的事件机制。选中这个选项可以使待创建的COM对象具有发出事
件的能力。缺省情况下该选项不被选中。 对象对自由线程调度的支持(Free Thread Marshaller, 简称FTM) 对象的自由线程调
度是对象在处于自由线程模型状态下,为了简化对象的访问过程而采用的一种优化策略。缺省情况下该选项不被选中。 对于上述的
任何一个选项的详细描述都涉及到COM技术一些核心的内容,并且都已超出本文的范围,因此本文只对ATL给出的缺省选项加以说明,
对这些内容感兴趣的读者可以参考Microsoft提供的文档。 完成了上面的设置以后,就可以按“OK”按钮完成对象的创建过程。下
一步就是向所生成的ATL类的接口中加入成员函数的定义,以及接口成员函数的实现过程。
3.、加入接口定义,实现接口函数
加入了ATL类定义之后,我们可以打开Visual C++集成环境下项目管理器(Workspace)中的Class View来检查生成的类定义的情况。
我们可以看到一个新的类已经生成,同时,还生成了相应的接口定义。ATL Object Wizard为我们生成了类定义的.h 和.cpp文件,此外
还有用于接口定义的IDL文件。有了这些文件以后,我们就可以为接口加入成员函数,完成类的定义。 首先在Class View中选中相
应的接口,显示为接口IATLTest,单击鼠标右键打开菜单,如图7。此弹出式菜单定义了为接口加入属性和方法的操作。选取其中
的“Add Method...”项,可以为接口加入方法成员;选取“Add Property...”则可以为接口加入新的属性成员。 加入属性和方法
的对话框可以参看图8和图9。如果我们要在接口中加入一个方法,则选取“Add Method...”菜单命令。假设方法名为ABC,方法的返
回类型为COM规定的HRESULT类型。我们也可以定义非HRESULT返回类型的函数,但是这需要手工修改接口定义的IDL文件。我们定
义ABC方法的一个参数为a,类型为整数型。完成了方法的定义以后,单击“OK”按钮则把此方法加入到接口中。 属性的加入过程
是类似的。属性加入对话框要求指定属性的类型、名字以及属性的访问方式。在属性和方法的编辑对话框中都有一个“Attributes”按
钮,在给出了一个属性或方法的基本定义之后,单击此按钮,可以对属性和方法的一些高级特性进行设置。 方法成员加入以后,我
们可以通过Class View来检查ATL为我们所做的工作。首先我们看到ATL在接口的定义中加入了该方法的定义;同时在对应的ATL类定义
中,也加入了一个相应的方法的定义;在类对应的.cpp文件中,加入了此方法的实现框架。此后,我们只要在这个函数框架中加入该方
法的代码逻辑,一个接口函数的定义和实现就基本完成了。依照这种方式,我们可以完成整个COM对象的定义和实现。 完成以上
的步骤之后,我们就可以编译连接应用了。
4、 编译连接应用、注册COM服务程序
对ATL工程的编译连接过程包括下面的几个步骤: 使用MIDL编译工程的IDL文件,形成接口定义的头文件和用于调度(Marshalling)
的代码; 编译工程的.cpp文件形成目标文件; 连接目标文件,形成应用模块; 注册COM服务程序。 关于工程编译
连接的其它部分同Visual C++中MFC工程的编译连接过程相似,这里只重点介绍一下COM服务程序的注册过程。 在ATL中,COM
服务程序的注册是在工程编译连接的最后阶段,由ATL辅助完成的。在手工的COM编程中,服务程序的注册是比较麻烦的工作。在ATL
中,系统通过读取在建立工程过程中形成的注册脚本文件来完成注册工作。注册脚本(Register Script 简称RGS)是ATL提供的文本方式的
注册辅助文件。下面是注册脚本文件的一个实例。 HKCR - 表示注册表中COM对象的注册项,是HKEY_CLASS_ROOT的缩写 {
AuthTest.ActiveXObject.1 = s 'ActiveXObject Class' { CLSID = s '' } - 对象的ProgID AuthTest.ActiveXObject = s 'ActiveXObject
Class' { CLSID = s '' } -对象的与版本无关的ProgID NoRemove CLSID -对象CLSID注册项 { ForceRemove = s 'ActiveXObject
Class' { ProgID = s 'AuthTest.ActiveXObject.1' VersionIndependentProgID = s 'AuthTest.ActiveXObject' InprocServer32 = s
'%MODULE% -服务器类型,表示DLL服务器 { val ThreadingModel = s 'both' -线程模型,这里是BOTH型 } } } } RGS文件包
含注册COM服务程序的各项内容,通常我们不必修改此RGS文件,必要时我们也可以手工修改RGS文件来定制模块的注册过程。
四. 应用ATL的一个例子
上面介绍了使用ATL创建一个COM服务程序的基本过程。在介绍过程中,我们实际上已经生成了一个COM服务程序的基本框架,只是
没有填写实际的内容。在下面部分,我们实际开发一个十分简单的COM服务程序,并且为它编写一段客户代码进行测试,使大家对使
用ATL开发COM服务程序的过程有一个全面整体的了解。
我们要开发的服务程序的功能很简单,它只实现一个接口,这个接口名字是ISimpleInterface,接口只有一个成员函数,叫做Welcome
。这个函数的功能只是输出一个“Hello World!”的字符串。
按照上一部分介绍的创建COM服务程序的步骤,我们进行如下的操作:
1 打开Visual C++集成开发环境;
2 创建一个称为SimpleTest的ATL工程;
3 在这个工程中插入新的对象,对象的名字是SimpleInterface;
4 设置接口ISimpleInterface的有关属性,使它成为一个双接口;
5 在对象的接口ISimpleInterface中加入方法Welcome;
6 打开ATL加入的Welcome方法的框架,可以看到如下的代码段: STDMETHODIMP CActiveXObject::get_TestProp(long *pVal) {
AFX_MANAGE_STATE(AfxGetStaticModuleState()) // TODO: Add your implementation code here return S_OK; }
7 将程序框架中的注释部分替换为下面的代码: ::MessageBox(NULL,_T(”Hello World!”),_T(”Welcome”), MB_OK); Welcome方
法被调用时将弹出一个消息框。
8 编译连接工程。 上面的步骤完成以后,我们就有了一个简单的COM服务程序,而且已经被注册到当前系统中。 下面我们要完
成一个简单的COM客户程序。一个COM客户程序简单地说是使用COM组件对象的程序。
客户程序调用COM对象的基本流程是:
创建COM对象的实例。这可以通过调用Windows系统的API函数CoCreateInstance来完成。 通过接口调用函数。 调用
IUnknown::Release释放COM对象实例 我们的客户程序是使用MFC编写的一个基于对话框的简单应用程序。具体的过程如下:
1 打开Visual C++集成开发环境; 创建一个称为SimpleClient的基于对话框的MFC工程; 在对话框中加入一个按钮,名字为
TEST; 在SimpleClient.cpp文件中加入如下的代码:
(1) 在cpp文件 #include “simpleclientdlg.h”之后加入下面的代码: #include “d:/simpletest/simpletest_i.h” // 根据需要修
改头文件的路径 加入的头文件是在编译COM服务程序过程中自动生成的,其中包含接口本身的定义、接口IID的定义和COM对象的
CLSID的定义。包含该头文件可以使客户程序能够使用COM服务程序。
(2) 在按钮TEST的消息控制函数中加入如下的代码: HRESULT hr; ISimpleInterface* pIntf = NULL; hr = CoCreateInstance
(CLSID_SimpleInterface, NULL, CLSCTX_SERVER , IID_ISimpleInterface, (void **)& pIntf); if(SUCCEEDED(hr)) { pIntf-
>Welcome(); pIntf->Release(); } 上面的代码首先通过系统API CoCreateInstance创建COM对象,得到接口的指针,然后调用接
口成员函数Welcome,最后通过IUnknown::Release()函数释放COM对象实例。 编译连接客户程序 最后,我们可以测试客户
程序是否正常运行。启动客户程序,当单击“TEST”按钮时我们可以看到弹出一个消息框,这正是我们的COM服务程序提供的功能。
========
ATL编程总结
http://blog.csdn.net/lee353086/article/details/7097440内容概要
[1] 在Visual Studio2008下使用Visual C++ ATL项目向导,完成一个COM服务( DLL),可在HTML中调用。
[2]用Visual Studio打包成安装文件, 在客户端自动注册。
假设读者有在Visual Studio 2008下的C++开发经验,主要是给自己看的,很多地方省略了。
正文
建立COM控件
第一步:选择[Visual C++]->[ATL Project],输入项目名称后,点击[OK]继续
第二步:项目向导中“Server type”选择“Dynamic-link library(DLL)”,“Additional options”选择“Allowmerging of
proxy/stub code”
第三步:为你的ATL项目(容器)添加供外部使用的Class (ATL Simple Object)。选项页 “ C++”的“Short name”输入栏中输入你
的Class名称,其它输入框会自动更新。
第四步:“Threading
model”选“Apartment”;“Interface”选“Dual”;“Aggregation”选“No”;“Support”选“Connection points”和“I
Object With Site(IE objects support)”。
第五步:在“Class View”中,右键单击要添加方法的Interface的名称,在弹出菜单中选择“Add Method”,添加方法。为参数列表
添加参数要注意,“retval”属性的参数只能放在参数列表的最后一个,并且只能有一个,要返回字符串,参数类型可以选择“BSTR*”
,要返回Long类型,参数类型可以选择“LONG *”。完成后,在函数体内添加代码。
第六步:添加IE支持
在你新的类名的H文件的“ publicIObjectWithSiteImpl<你的类名>,”代码段后面添加下面这个代码段“
publicIObjectSafetyImpl<你的类名,INTERFACESAFE_FOR_UNTRUSTED_CALLER|
INTERFACESAFE_FOR_UNTRUSTED_DATA>,”。
在“COM_INTERFACE_ENTRY(IObjectWithSite)”后面插入“COM_INTERFACE_ENTRY(IObjectSafety)”代码段。
第七步(最后一步):右键单击资源文件选择“View Code”找到“CompanyName”等信息做修改。修改资源文件的语言为“中文
(简体)”,否则,用户查看文件信息(你写的中文注释)会是乱码。
第八步:按F7编译Solution,如何没有错误,IDE会自动为你注册COM服务。你也可以使用regsvr32命令手动注册或反注册生成的DLL
文件。
测试COM控件
我们新建的这个COM服务用“ActiveXControl test Container”这个容器做测试,会找不到这个COM,我们的ATL项目生成的DLL可
能不是严格意义上的Active X控件的缘故。
用VB程序做测试
通过在VB项目里Add reference添加COM组件
示例代码如下
[vb] view plain copy
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e AsSystem.EventArgs) Handles Button1.Click
Dim objTestATL As Simple_ATLLib.First_ATL
Dim lngReturnValue As Long
objTestATL = New Simple_ATLLib.First_ATL
lngReturnValue = objTestATL.AddNumbers(5, 7)
MsgBox("The value of 5 + 7 is: " & lngReturnValue)
End Sub
其中“Simple_ATLLib”是项目名称加lib,“First_ATL”是你刚才新建的Classs名称,“AddNumbers”是你为这个Class新建的方法
名。
用HTML页面做测试
下面是示例代码,其中classid可以从First_ATL.rgs中查找,其中“First_ATL”是你要在HTML中实例化的Class的名称。
[html] view plain copy
<object classid="clsid:F0FF2E0D-A56B-40A4-A4D1-F84032606F20" id="Dean" name = "Dean" ></object>
<form id="form1" name="form1" method="post" action="">
<a href="#" onclick="return CallUSB();">js调用ActiveX测试</a>
<input id="Write" name="Write"type="button" value="vb调用ActiveX测试"/>
</form>
<SCRIPT LANGUAGE="JavaScript">
//JavaScript调用Demo
function CallUSB()
{
try{
varUSBContent = Dean.AddNumbers(5, 7);
alert(USBContent);
}catch (e) {
alert("错误号: " +e );
}
return false;
}
</SCRIPT>
配置安装包
第一步:在当前Solution中添加New Project,选择project类型为“[Other project Types]->[Setup and Deployment]->[Setup
Wizard]”。在向导的选项卡中选择“Primaryoutput from 你的ATL项目名称”,其它可以取默认值。
第二步:修改公司名称、语言类型、安装位置等信息。
第三步:“Detected Dependencies”中有些DLL你不需要打包进来,可以排除它们。
第四步(最后一步):点击你的“Primary output”的那一项,在属性窗口中找到“register”属性,它的默认值
为“vsdrpDoNotRegister”,改为“vsdrpCOMSelfReg”。这样你的程序在用户机器中安装好后,你的DLL也在用户机器中注册好了
。
其它
[1]在添加的ATL Simple Object类型的Class,public域里,可以修改原FinalRelease的声明为STDMETHOD(FinalRelease)();
然后在CPP文件里实现这个声明,可以实现当IE窗口关闭时,做一些对象清理工作。
遗留问题
[1]本文不包含数字签名的相关信息
[2]ActiveX在IE中正常,但是不能在Firefox中正常运行
========
ATL编程初级教程
http://www.cnblogs.com/weiqubo/archive/2011/01/29/1947540.html介绍
本教程的目的是告诉你如何使用ATL创建一个COM服务器,并使用Visual C++和Visual Basic程序来分别调用这个服务器。我并不
想深入探讨COM的细节,也不想让你深陷于IDL之中。这一教程只是为VC++的新手程序员设计的,告诉他们利用ATL来创建一个COM
对象有多么简单,并让他们能对ATL产生更多的兴趣。
第1步:启动ATL COM Wizard
你所需要做的第一件事情就是启动Visual C++并创建一个新的工程,选择“ATL COM Wizard”,工程名为“Simple_ATL”。设
置好工程的路径之后,单击OK按钮。你会看到,屏幕上给了你若干选项。第一个选项为“Server Type”。我们将要创建一个服务器
DLL,所以请确认服务器的类型选为“Dynamic Link Library”。我们并不需要关心下面的其它三个复选框,所以我们可以将它们忽略
掉。按下Finish按钮,这样向导就会为你产生适当的文件了。之后,一个“New Project Information”窗口就会出现,你可以从上面
得知向导都会创建什么文件,按下“OK”接受这一切。
第2步:创建一个新的ATL对象
请确认你能在VC++的IDE中看到Workspace View,如果不能的话则请单击“View”菜单,然后选择“Workspace”。在这个视
图中你会看到三个选项卡,请单击“ClassView”栏,你应该会看到“Simple_ATL Classes”。请在此右击鼠标键,并在弹出菜单中选
择“New ATL Object”,你将会看到下面这样的窗口:
默认的选择项“Simple Object”就是我们所要的了,请单击next按钮,你会来到“ATL Object Wizard Properties”窗口中。在
“Short Name”文本框中输入“First_ATL”。请注意,这时候向导就会自动地填写其它的文本框。然后,单击顶部的“Attributes”
标签,在这里你需要做一些选择。第一项线程模型(Threading Model)的选择,我们选择默认的单元(Apartment)模型。对于接口
(Interface),我们选择双重(Dual)。最后,因为我们的程序与聚合(Aggregation)无关,所以我们选择“No”的单选按钮。你
不必关心底部的三个复选框,直接单击OK就可以了,这时候向导就会为我们创建一个新的ATL简单对象。
第3步:添加一个方法
如果你现在在工作区中单击了“ClassView”标签,那么你会注意到向导在其中添加了一串东西。我们想添加的第一个东西是一个
方法,可以在“IFirst_ATL”上右击鼠标键,并选择“Add Method”。
一旦你单击了“Add Method”之后,你就会看到“Add Method to Interface”窗口。在返回值类型(Return Type)处你会看
到,这个方法会默认返回HRESULT,在大多数情况下你不需要改变它。下一个文本框允许我们输入方法的名称,我们可以输
入“AddNumbers”。最后一个文本框是让我们输入参数的,由于我们想做两个数的相加并获得一个返回的结果,所以我们需要三个参
数,并且最后一个参数是一个指针。现在,我们不必看那关于IDL的300页教程了,可以直接在参数文本框中输入:
[in] long Num1, [in] long Num2, [out] long *ReturnVal
简单地说来,我们声明了两个long类型的参数,这两个值是传入的([in]),还有一个最后传出的返回值结果([out])。(你第一
次看到这样的东西可能会有些奇怪,但是如果你读了一两本关于COM的书的话,就会觉得亲切多了。)现在就可以单击OK按钮了。然
后,单击“ClassView”标签,并展开所有的“+”标志,使得树型视图完全展开。你会在接口(IFirst_ATL)的顶部看到我们
的“AddNumbers”方法以及我们给予它的参数。在这个方法上双击鼠标键,并插入以下的代码:
STDMETHODIMP CFirst_ATL::AddNumbers(long Num1,
long Num2, long *ReturnVal)
{
// TODO: Add your implementation code here
*ReturnVal = Num1 + Num2;
return S_OK;
}
第4步:编译DLL
无论你相信与否,你已经拥有一个用ATL编写的COM服务器了!当然,我们还需要编译它。请按下F7键,这样VC++就可以编译了
。编译器工作片刻后就会在注册表中注册你的新DLL了,这样一来其它的程序就可以使用它了。让我们来测试一下。
第5步:在Visual Basic中测试COM服务器
那么,先让我们用VB来测试这个COM服务器吧。(如果你没有VB的话,你可以跳过这一节,直接在VC++中测试。)启动VB,并
选择“标准EXE(Standard EXE)”建立工程,并在对话框上放置一个命令按钮。现在,我们需要添加COM服务器的引用,请单击“
工程(Project)”菜单并选择“引用(References)”,找到“Simple ATL 1.0 Type Library”并选择它。
单击确定(OK)按钮之后,你可以双击先前放置的命令按钮,VB会切换到这个按钮的代码窗口。添加以下的代码:
Private Sub Command1_Click()
Dim objTestATL As SIMPLE_ATLLib.First_ATL
Set objTestATL = New First_ATL
Dim lngReturnValue As Long
objTestATL.AddNumbers 5, 7, lngReturnValue
MsgBox "The value of 5 + 7 is: " & lngReturnValue
Set objTestATL = Nothing
End Sub
如果你是个VB的程序员,那么这些代码对于你是很直观的:我们声明了一个对象,并从COM服务器调用“AddNumbers”的方法
,然后显示结果。现在按下F5来运行这个VB工程,单击命令按钮,你就会看到期望的结果了:
并不是很难吧?那么我们再来一次,这一次用VC++。
第6步:在Visual C++中测试COM服务器
如果你的Simple_ATL工程仍然开着,那么就关了它并创建一个新工程。选择“Win32 Console Application”,起名为“Test_ATL
”,在下一个窗口中单击OK按钮接受所有默认值,最后单击Finish按钮。现在,你应该有了一个空工程。那么,按下Ctrl+N为工程加入
一个新文件,选择“C++ Source File”并命名为“Test_ATL.cpp”,单击OK接受。你现在应该有了一个打开的空白文件,我们需要在
其中添加一些代码来测试COM服务器。代码如下:
// 你需要指明Simple_ATL工程的路径来引用这个头文件
#include "..\Simple_ATL\Simple_ATL.h"
#include <iostream.h>
// 把以下的内容从Simple_ATL工程目录的Simple_ATL_i.c文件中复制过来
// 注意:你也可以直接包含Simple_ATL_i.c文件,我在此只想清楚地表明这些const常量来自何处以及它们的样子
const IID IID_IFirst_ATL =
{0xC8F6E230,0x2672,0x11D3,
{0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}};
const CLSID CLSID_First_ATL =
{0x970599E0,0x2673,0x11D3,
{0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}};
void main(void)
{
// 声明一个HRESULT变量以及一个Simple_ATL接口的指针
HRESULT hr;
IFirst_ATL *IFirstATL = NULL;
// 现在初始化COM
hr = CoInitialize(0);
// 使用SUCCEEDED宏来看看我们是否能够获得接口的指针
if(SUCCEEDED(hr))
{
hr = CoCreateInstance( CLSID_First_ATL, NULL,
CLSCTX_INPROC_SERVER,
IID_IFirst_ATL, (void**) &IFirstATL);
// 如果成功了,那么调用AddNumbers方法
// 否则给用户显示一条适当的信息
if(SUCCEEDED(hr))
{
long ReturnValue;
IFirstATL->AddNumbers(5, 7, &ReturnValue);
cout << "The answer for 5 + 7 is: "
<< ReturnValue << endl;
IFirstATL->Release();
}
else
{
cout << "CoCreateInstance Failed." << endl;
}
}
// 卸载COM
CoUninitialize();
}
第7步:编译并运行程序
现在你可以按下F5键来编译程序,然后按下Ctrl+F5来运行之。你应该可以看到一个DOS窗口,给出了你所期望的结果。
分类: ATL
========
相关文章推荐
- VC学习资料收集(12):VC小知识总结
- 学习笔记总结(VC)
- 编写VC Makefile的学习总结
- VC学习笔记---ATL MFC CLR三个库的区别
- VC访问数据库学习总结
- VC实例学习 (1):总结下今天学习的东西
- VC++ 字符串操作学习总结
- vc++学习总结2
- VC消息学习总结
- VC++调试技巧学习总结
- 学习笔记总结(VC)
- ATL学习实践(VC8)-用CWindowImpl实现窗口
- VC的邮槽学习笔记总结
- vc++学习总结3
- VC++中,什么是ATL,STL,SDK?推荐几本学习教材
- 转贴:VC++中对于处理消息的学习总结
- VC的匿名管道学习笔记总结
- [技术学习]VC++ 的MFC 和ATL 及COM 是什么?
- ATL建立Com的相关学习和编程总结
- VC++ 自定义消息学习总结