使用ATL开发COM组件.docx
- 文档编号:6263768
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:15
- 大小:369.55KB
使用ATL开发COM组件.docx
《使用ATL开发COM组件.docx》由会员分享,可在线阅读,更多相关《使用ATL开发COM组件.docx(15页珍藏版)》请在冰豆网上搜索。
使用ATL开发COM组件
使用ATL开发COM组件
ATL是用来开发COM组件的类库,是VC中继MFC之后的第二大类库,内容也非常多,短时间之内不可能学完。
我们这里只是抛砖引玉。
实用率:
30%不到。
一、COM原理
1、什么是COM?
COM是组件对象模型的简写(ComponentObjectModel),它是一套二进制对象模型,可以跨平台、跨语言、跨网络(分布式的),也称为COM组件。
它可以用任何语言编写,都能完成相同的功能,并能够复用。
软件的复用有五类:
源代码复用,模块复用,接口复用,程序复用,程序架构复用。
COM组件技术是模块复用的最高形式。
用组件开发软件象搭积木一样,可以拼装成一个大组件或大系统。
COM并不是一种语言,而是一种组件开发的标准。
它描述了对象模型建立,对象间的通信等,因此COM更象一个二进制组件重用的协议。
与COM有关的程序员有两种:
组件开发者,组件使用者。
2、COM组成
COM组件是由以Win32动态链接库(DLL)或可执行文件(EXE)发布的代码所组成。
3、为什么要学习COM
传统的软件开发模式:
传统的软件应用程序发布以后,使用者想得到更完善的软件或者去掉其中的某些内容,只有等软件提供商发布新的版本以后,使用者的这一梦想才能得以实现。
使用COM组件以后:
软件开发人员可以在软件版本发布以后修改或者去掉软件某个不需要部分。
对应用程序在更高的层次上定制,使得软件更具灵活性、动态性。
是未来应用软件开发的趋势(10年前可以这么说,现在未必)。
4、COM的前身是OLE(ObjectLinkingandEmbedding),即对象链接与嵌入。
5、组件:
如积木一样,具有“块”的概念,可以动态的将他们插入或卸出应用程序。
这就需要两个条件:
第一,组件必须动态链接(不因自己的位置改变而改变自身形式);第二,组件必须隐藏内部实现细节(独立于具体编程语言,二进制形式发布)。
每个组件相当于一个黑盒子,对外提供的只是接口(函数)。
如果接口没有发生任何变化时,对组件的修改几乎不会影响应用程序的其它部分。
提供服务的组件称为服务器组件,使用服务的组件称为客户组件。
6、COM的设计思想
COM的设计思想是为了重用,而且是二进制级别的代码重用。
类库也是重用,如MFC,但只是基于源码级别的重用,类库严重依赖于固定的某种语言,如MFC依赖于VC,PFC依赖于PowerBuilder等。
DLL也是重用,但也有很大的局限:
函数重名问题、各编译器对函数的名称修饰不兼容问题、路径问题、DLL与EXE的依赖问题。
COM没有重名问题,因为根本不是通过函数名来调用函数,而是通过虚函数表,自然也不会有函数名修饰的问题。
路径问题也不复存在,因为是通过查注册表来找组件的,放在什么地方都可以,即使在别的机器上也可以。
也不用考虑和EXE的依赖关系了,它们二者之间是松散的结合在一起,可以轻松的换上组件的一个新版本,而应用程序混然不觉。
7、学习COM的目的
要学COM的基本原理,推荐看《COM技术内幕》。
但仅看这样的书是远远不够的。
其实,我们最终的目的是要学会怎么应用COM去编写我们的应用程序,而不是拼命的研究COM本身的机制。
所以我个人觉得对COM的基本原理不需要花大量的时间去追根问底,没有必要,是吃力不讨好的事。
其实我们只需要掌握几个关键概念就够了。
8、用VC开发COM组件所要了解的几个关键概念
(1)、COM组件实际上是一个C++类,而接口都是纯虚类。
(2)、COM组件有三个最基本的接口类,分别是IUnknown、IClassFactory、IDispatch,其中,IUnknown包含三个函数,分别是QueryInterface、AddRef、Release。
(3)、Dispinterface接口、Dual接口以及Custom接口
(4)、COM组件有三种:
进程内COM、本地COM、远程COM。
即它可以是进程内的,即和调用者在同一个进程内;也可以和调用者在同一个机器上但在不同的进程内;还可以根本就和调用者在两台机器上。
(5)、COM组件的核心是IDL
IDL是一种用来定义COM接口规范的、大家都认识的接口定义语言,用它来定义的接口,不论放到哪个语言平台上都认识它。
用VC,VB等语言都可以开发COM组件,开发好的COM组件也可以被其他语言调用。
(6)、注册表在COM中的重要作用
首先要知道GUID的概念,COM中所有的类、接口、类型库都用GUID来唯一标识,GUID是一个128位的字串,根据特制算法生成的GUID可以保证是全世界唯一的。
COM组件的创建接口、查询接口都是通过注册表进行的。
有了注册表,应用程序就不需要知道组件的DLL文件名、位置,只需要根据CLSID查就可以了。
当版本升级的时侯,只要改一下注册表信息,就可以神不知鬼不觉的转到新版本的DLL。
(7)、一个典型的自注册的COMDLL所必有的四个函数
●DllGetClassObject:
用于获得类厂指针
●DllRegisterServer:
注册一些必要的信息到注册表中
●DllUnregisterServer:
卸载注册信息
●DllCanUnloadNow:
系统空闲时会调用这个函数,以确定是否可以卸载DLL
(8)、COM组件的运行机制
●通过查注册表CLSID_Object,得知组件DLL的位置、文件名
●装入DLL库
●使用函数GetProcAddress(...)得到DLL库中函数DllGetClassObject的函数指针
●调用DllGetClassObject
9、完整的COM组件的接口实现示例:
代码见“1.1.ComInterface1”工程,这里无需掌握,只是帮助理解COM的原理。
10、增加查询组件接口QueryInterface()、应用计数增加接口AddRef()、应用计数减少接口Release()后的完整例子。
代码见“1.2.ComInterface2”工程,这里无需掌握,只是帮助理解COM的原理。
二、ATL活动模板库(ActiveTemplateLibrary)
在ATL产生以前,开发COM组件的方法主要有两种:
一是使用COMSDK直接开发COM组件,另一种方式是通过MFC提供的COM支持来实现。
但是这两种方法都非常的复杂、麻烦。
使用ATL开发COM应用是一件比较简单的事情,但是在ATL简单易用的界面后面却包含着复杂的技术。
这些技术包含以下一些方面:
●COM技术
●C++模板类技术(Template)
●C++多继承技术(Multi-Inheritance)
其中,COM技术本文开头有所描述。
C++模板类技术(Template)、C++多继承技术(Multi-Inheritance)在C++理论课中已有详尽描述。
这里最主要的是介绍使用ATL怎么生成一个自己的COM组件,以及怎么使用该组件。
预备知识:
ATL中的数据类型BSTR
BSTR是BASIC中字符串类型的表示方式,是一个指向UNICODE字符串的指针。
有关BSTR的处理函数,参见下表。
API函数
说明
SysAllocString()
申请一个BSTR指针,并初始化为一个字符串
SysFreeString()
释放BSTR内存
SysAllocStringLen()
申请一个指定字符长度的BSTR指针,并初始化为一个字符串
SysAllocStringByteLen()
申请一个指定字节长度的BSTR指针,并初始化为一个字符串
SysReAllocStringLen()
重新申请BSTR指针
CString函数
说明
AllocSysString()
从CString得到BSTR
SetSysString()
重新申请BSTR指针,并复制到CString中
CComBSTR函数
ATL的BSTR包装类。
在atlbase.h中定义
Append()、AppendBSTR()、AppendBytes()、ArrayToBSTR()、BSTRToArray()、AssignBSTR()、Attach()、Detach()、Copy()、CopyTo()、Empty()、Length()、ByteLength()、ReadFromStream()、WriteToStream()、LoadString()、ToLower()、ToUpper()
运算符重载:
!
!
=,==,<,>,&,+=,+,=,BSTR
太多了,但从函数名称不能看出其基本功能。
详细资料,查看MSDN吧。
另外,左侧函数,有很多是ATL7.0提供的,VC6.0下所带的ATL3.0不支持。
由于我们将来主要用ATL开发组件程序,因此使用ATL的CComBSTR为主。
ATL提供了CComBSTR类来简化使用BSTR(见上表)。
ATL中的数据类型VARIANT
C++、BASIC、Java、Pascal、Script......计算机语言多种多样,而它们各自又都有自己的数据类型,COM产生目的,其中之一就是要跨语言。
而VARIANT数据类型就具有跨语言的特性,同时它可以表示(存储)任意类型的数据。
ATL提供CComVariant类来简化使用VARIANT,如:
VARIANTv=CComVariant(任意C++类型);
下面我们使用ATL编写一个“将一个字符串转换成大写然后倒置”的COM组件:
1.建立一个ATLCOMAppWizard工程AtlComSample:
2.选择创建的COM类型:
该步骤中的一些选项说明:
动态连接库(DLL):
最终产生一个动态连接库形式的COM服务程序(DLL);
应用程序(Executable):
最终产生一个自注册的可执行的COM服务程序(EXE);
NT服务(Service):
产生一个以NT服务方式运行的COM服务程序(EXE)。
允许嵌入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提供的各种功能强大的类的支持,而不必直接使用WindowsSDK。
从另一个方面来看,在ATL工程中使用MFC同时就丧失了ATL代码轻量级的特点。
支持MTS。
MTS是MicrosoftTransactionServer的缩写,它是Microsoft在COM技术方面的一个新的分支,这里不做详细说明。
----完成上面的设置以后,可以选择Finish完成工程的设置,ATL将创建相应的工程。
我们选择默认选项,不做任何改动。
3.向工程中加入一个新的ATL类:
首先通过集成环境的"Insert"菜单下的"NewATLObject..."命令进入"ATLObjectWizard"对话框。
如下图所示:
对话框的左边部分说明了待创建对象的基本类型,这里主要有以下几种类型:
●对象(Object):
基本的COM对象类型;
●控件(Control):
ActiveXControl类型的ATL对象;
●其他(Miscellaneous):
辅助功能,如对话框的生成等;
●数据访问(DataAccess):
数据访问,支持MTS等。
对于我们这个一般的COM服务程序,左侧选择对象(Object),右侧选择SimpleObject,点击下一步继续:
4.输入我们这个组件的类名CMyString,其他名字会自动产生,不做改动,点确定:
5.切换到Attributes(属性)标签页:
对象的属性设置是ATL对象创建过程中最复杂的部分,包括以下几个主要部分:
对象的线程模型(ThreadModel):
对象的线程模型是COM对象在多线程环境下被访问时对访问方式的控制,缺省情况下在ATL中采用的是套间模型Apartment,由系统通过消息队列方式提供并发控制。
对象的接口模型(Interface):
COM对象的接口可以是双接口(DualInterface)。
双接口不同于普通接口(CustomInterface)之处在于双接口是从Automation基本接口IDispatch继承的,而普通接口是从IUnknown接口直接继承来的。
缺省的接口模型是双接口。
对象的聚合模型(Aggregate):
COM规范不允许对象的实现继承,但是可以通过聚合方式重用其他的COM对象。
ATL对象属性设置中的聚合模型可以指定待创建的COM对象是否支持聚合模型。
缺省的选项是支持对象的聚合。
对象对错误处理的支持(SupportISupportErrorInfo):
选取这个选项可以在对象的运行过程中支持错误处理。
缺省情况下这个选项不被选中。
对象对连接点的支持(SupportConnectionPoints):
连接点是COM对象的事件机制。
选中这个选项可以使待创建的COM对象具有发出事件的能力。
缺省情况下该选项不被选中。
对象对自由线程调度的支持(FreeThreadMarshaller,简称FTM):
对象的自由线程调度是对象在处于自由线程模型状态下,为了简化对象的访问过程而采用的一种优化策略。
缺省情况下该选项不被选中。
这里我们也使用默认选项,确定。
此时在“ClassView”标签页会增加一个CCMyString类和一个ICMyString接口。
6.为ICMyString接口添加一个方法StringTransfer(),其原型我们定义如下:
HRESULTStringTransfer([in]BSTRInData,[out]BSTR*OutData,[out,retval]long*result);
其中,[in]表示参数方向是输入;[out]表示参数方向是输出;[out,retval]表示参数方向是输出,同时可以作为函数运算结果的返回值。
一个函数中,可以有多个[in]、[out],但[retval]只能有一个,并且要和[out]组合后在最后一个位置。
在CmyString.cpp中,给添加的方法加入如下代码:
CComBSTRstrSource=InData;
CComBSTRtempSource=InData;
boolbNeedToUpper=true;
intj=(int)strSource.Length()-1;
//实现字符串到大写字母的转换并进行逆序转换
for(inti=0;i<(int)strSource.Length();i++)
{
if(strSource[i]>='a'&&strSource[i]<='z'&&bNeedToUpper)
{
strSource[i]=strSource[i]-32;
bNeedToUpper=true;
}
if(strSource[i]=='')bNeedToUpper=false;
tempSource[j]=strSource[i];
j=j-1;
}
*OutData=tempSource;
return*result;
编译链接,通过。
COM组件开发完毕。
检查生成的文件,发现系统在Debug目录下生成了一个动态链接库文件AtlComSample.dll,在工程目录下生成了一个类型库文件AtlComSample.tlb。
这2个文件就是用ATL开COM组件的成果。
你现在就可以发布这2个文件给另外的COM使用者了。
其中的DLL文件就是COM组件,使用之前必须使用RegSrv32.exe进行注册。
TLB文件是提供给开发者使用的,在后面使用COM组件的例子中我们会看到是如何使用该TLB文件的。
直接在DOS执行RegSvr32命令,得到如下的用法提示:
注册一个COM组件的命令:
regsvr32c:
\aa\xyz.dll
取消注册COM组件的命令:
regsvr32/uc:
\aa\xyz.dll
注册一个组件或者取消注册一个组件,都会在注册表中有所反应。
其实,编译之后,VC已经在背后帮我们自动注册好了该COM组件。
使用注册表编辑器RegEdit.exe查找AtlComSample,可以发现我们这个组件已经被注册好了,见下图:
注意其中CurVer下的一个字符串:
“AtlComSample.CmyString.1”,它是我们引用这个组件的ProgID。
下面我们在VC中来使用这个组件。
6.另外新建一个MFC对话框工程MycomClient,并添加工程到当前工作区中:
7.使用MFC类向导将上个工程中开发好的组件AtlComSample添加到当前工程中:
类向导AddClassFromatypelibrary选择AtlComSample.tlb文件打开。
之后,你会发现在ClassView标签页下多了一个类:
ICMyString。
这个就是导入进来的COM组件的类,其中包含了我们在上个工程中所写的StringTransfer函数。
同时在项目目录下多了2个文件:
AtlComSample.h和AtlComSample.cpp。
下面我们就可以使用它了。
8.设计如下对话框界面:
关联如下变量:
对“字符串转换”按钮添加如下响应代码:
#include"atlcomsample.h"//别忘了加COM组件的头文件
voidCMyComClientDlg:
:
OnBtnTransfer()
{
ICMyStringm_MyString;
//创建COM对象:
这里的字符串一定要和注册表中的ProgID一致!
!
!
if(!
m_MyString.CreateDispatch("AtlComSample.CmyString.1"))
MessageBox("创建COM组件失败:
请检查ProgID是否正确,组件是否已经注册");
UpdateData(true);//得到源字符串放到m_SourceString中
BSTRbstrDestStr=SysAllocString(L"");
m_MyString.StringTransfer(m_SourceString,&bstrDestStr);//调用COM接口
m_DestString=bstrDestStr;//得到转换后结果字符串
UpdateData(false);//将结果字符串显示到编辑框中
}
运行结果如下:
总结:
1、用ATL开发COM组件:
作业:
1、参考上例,使用ATL建立一个COM组件接口MiniStringCom,实现2个接口函数:
First2Upper“将给定字符串首字母大写化”,MergeString“将给定的2个字符串合并成1个字符串”,并在客户程序中进行使用。
2、选修:
在MSDN中查找“ATLTutorial”,即可找到微软提供的用ATL开发COM组件的教程。
按照该教程中的7个步骤,实现一个用多边形逼近圆的图形算法。
有时间则翻译并讲解。
3、选修:
阅读文章《COM组件设计与应用.mht》
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 ATL 开发 COM 组件
![提示](https://static.bdocx.com/images/bang_tan.gif)