您好,欢迎访问三七文档
组件技术基础培训教程何珍文zwhe@hotmail.com内部资料第一章COM开发、使用及相关技术既然本书讨论的是组件式GIS,那首先还是必须了解COM组件的。在这本书中我不想详细的讨论COM组件,对于COM组件方面的技术与知识,我的原则就是够用就好了;但我们还是得花一些篇幅来讨论组件的开发和使用问题。如果你想了解COM比较底层的东西,我建议你去看一下《COM技术内幕》这本书。在这里,我们关心的问题只是怎么利用现有的编程工具来实现我们设计的组件,并怎样在这些编程工具中使用它们。我这里采用的设计工具是RationalRose2007,编程工具采用的是VisualStudio.Net2005,采用的COM编写语言是C++。如果你采用的还是VisualC++6.0或更低的版本,那么这里讲的属性化将不适合于你;你只能选择回到IDL(接口定义语言)时代,或者升级你的开发工具。随着编程开发工具软件的不断发展,COM组件的编写也越来越简单了。我们先用VisualStudio.net2005做一个简单的组件库,然后再看看怎样在不同的环境中使用这个组件。希望通过这个过程让读者对组件有一个比较直观简洁的认知。1、COM组件的开发方法首先,我们来设计一个简单的计算器组件Calculator。在这个组件中我们将实现两个实数的加法与减法运算功能。其UML表示如下图1‐1所示。ICalculatorAdd()Subtract()Calculator图1‐1计算器组件Calculator的UML表达接下来,我们开始这个组件库的开发工作。Step1:打开VisualStudio.Net2005,建立一个解决方案或项目Calculator。在项目类型中选择VisualC++下的ATL选项,在模板中选择”ATL项目”,输入工程名称Calculator。选择“创建解决方案目录”,单击“确定”,在指定的目录下将创建Calculator解决方案和Calculator的项目。图1‐2ATL新建项目Step2:设置应用程序的属性,在这里选择属性化和动态连接库具体如下图所示。图1‐3ATL项目项目应用程序设置对于上面的图中的选项说明如下:属性化支持属性化编程,是未来的发展方向,是IDL方案的替代方案。建议采用属性化选项,它能简化很多繁琐的IDL编程工作。动态链接库(DLL)表示建立一个DLL的组件程序。可执行文件(EXE)表示建立一个EXE的组件程序。服务(EXE)表示建立一个系统服务组件程序,系统启动后就会加载并执行的程序。允许合并代理/存根(stub)代码选择该项表示把“代理/存根(Stub)”代码合并到组件程序中,否则需要单独编译,单独注册代理存根程序。支持MFC建议不要选择,除非有特殊的原因,比如我们原来的程序是基于MFC的,我们的组件必须要MFC的支持。一般在写ATL程序,昀好不要选择该项。但是很多VC程序员对于MFC的数据集合类和字符串类依赖很大,建议采用STL中的相关类进行替代。具体替换方案:1、std::string代替MFC中的CString;2、std::vector代替MFC的数组类如CArray,CPtrArray等;3、std::list替换MFC中的CList等列表类;4、对于BSTR建议采用CComBSTR类,或_bstr_t类;支持COM+1.0支持事务处理的COM+功能。上面这些只需要了解一下就行了。接着点击完成按钮。将生成两个工程。如下图。图1‐4ATL新建项目列表Calculator是我们将要修改的主题工程,CalculatorPS是Calculator的存根代理工程。Step3:添加组件,也就是添加ATL对象类。在Calculator工程上点击右键,添加类,弹出如下对话框。在类别中选择ATL。在模板中会出现在本机上已经安装的ATL对象模板。在这里我们选择“ATL简单对象”。对于“ATL简单对象”,模板中仅仅只是实现了IUnknown接口。除了这个模板外,我们还可以使用“ATL控件”,“ATL对话框”等上十个模板选项。对于这些选项我们在后面的章节用到的时候再作详细介绍。图1‐5添加ATL类单击“添加”按钮,在简称中输入“Calculator”出现如下界面:图1‐6填写ATL对象名称单击“下一步”,出现一个错误提示。怎么办?图1‐7名称冲突错误大家记得我们的工程名字和组件名称是一样的,所以我们在修改组件的文件名称,避免重复。如下:图1‐8ATL对象名称修改对于接口名称我们也可以作修改。要注意的是ProgID,默认的ProgID构造方式为“项目名.简称名”,这个是我们在后面使用组件中可能用到的。可以通过“Calculator.Calculator.1”来导入组件,创建组件。关于这个我们在后面的章节要讲到的,这里不再详述。单击“下一步”,出现组件选项界面:线程模型COM中的线程,这是一个昀复杂的部分,如果想了解可以参看《COM技术内幕》。我们都选单元(Apartment),它代表当在线程中调用组件函数的时候,这些调用会排队进行;我们可以暂时不用考虑同步问题。接口双重(Dual),这个非常重要,也非常常用的,为了能够使组件能够在脚本中使用,必须使用这个接口,所以在ComGIS我们一般都要实现双接口,以便WebGIS的实现,今天制作的是接口也是从IDispatch接口集成,所以请选择“双重”按钮。聚合我们编写的组件,将来是否允许被其他人以聚合方式(有聚合和包容两种方式)使用。“只能创建为聚合”,有点类似C++或Java中的不能直接创建实例的虚类,如果不是处于设计目的,一般这个选项不用。大多数情况下支持“聚合”不会错,所以我们第一次作组件选择“是”。ISupportErrorInfo是否支持丰富信息的错误处理接口。连接点是否支持连接点接口(事件、回调)。IObjectWithSite是否支持IE的调用。图1‐9ATL对象选项选择项如图1‐9所示。单击完成,得到一个CCalculator类和ICalculator接口。图1‐10Calculator类与接口由于我们选择了“属性化”,所以,这两个对象的定义在统一个头文件”CalculatorX.h”(记得吗,我们该过名字)。关于接口的实现则在”CalculatorX.cpp”中。在我们还没有给接口添加任何方法和属性之前,我们来看看自动生成的代码。代码1‐1Calculator类与接口//ICalculator接口定义说明,语法与原来的IDL一样。[object,//接口的唯一ID,等价于我们后面要用到的IID_ICalculatoruuid(6B78CAD1-0532-4AE7-895A-F76AF146AA1B),dual,//双接口helpstring(ICalculator接口),pointer_default(unique)]__interfaceICalculator:IDispatch//从IDispatch接口继承{};//CCalculator的coclass对象[coclass,default(ICalculator),//组件的默认接口ICalculatorthreading(apartment),//组件线程模式,我们选择了apartmentvi_progid(Calculator.Calculator),progid(Calculator.Calculator.1),//组件Calculator的ProgIDversion(1.0),//组件Calculator的唯一ID,等价与后面的CLSID_CCalculatoruuid(D847DC60-2B09-4B9F-A9AC-F9DDCE7030F6),helpstring(CalculatorClass)]classATL_NO_VTABLECCalculator:publicICalculator//该类实现ICalculator接口{public:CCalculator(){}DECLARE_PROTECT_FINAL_CONSTRUCT()HRESULTFinalConstruct(){returnS_OK;}voidFinalRelease(){}};上面这段代码定义了ICalculator接口以及它的实现组件类对象CCalculator。Step4:添加接口方法。右键单点击ICalculator,弹出菜单,选择“添加方法…”,弹出如图1‐11所示的界面。在这个界面中我们可以给接口ICalculator添加方法。[in]表示参数方向是输入;[out]表示参数方向是输出;[out,retval]表示参数方向是输出,同时可以作为函数运算结果的返回值。一个函数中,可以有多个[in]、[out],但[retval]只能有一个,并且要和[out]组合后在昀后一个位置。关于这些规则可以参考IDL的语法说明。首先,我们添加Add方法,在名称内填写方法名称,添加两个[in]DOUBLE参数a,b;添加一个返回参数[out,retval]DOUBLE*c。然后单击“下一步”进入如图1‐12所示的IDL属性界面。IDL的语法上对这个关键字都有详细的说明,在这里不加描述;以免刚开始就陷入具体细节。这一页我们只是对这个方法的注释字符串进行改动,在“helpstring”中加入对这个方法的说明“实现两个实数的加法运算功能,返回运算结果”。图1‐11给接口添加方法图1‐12接口添加方法的IDL属性项设置在如图1‐12中单击“完成”,VisualStudio.Net2005会自动添加如下代码,变动的代码以黑体和斜体表示。具体见代码代码1‐2。代码1‐2Calculator类与接口//ICalculator接口定义说明,语法与原来的IDL一样。[object,//接口的唯一ID,等价于我们后面要用到的IID_ICalculatoruuid(6B78CAD1-0532-4AE7-895A-F76AF146AA1B),dual,//双接口helpstring(ICalculator接口),pointer_default(unique)]__interfaceICalculator:IDispatch//从IDispatch接口继承{[id(1),helpstring(实现两个实数的加法运算功能,返回运算结果),helpcontext(1)]HRESULTAdd([in]DOUBLEa,[in]DOUBLEb,[out,retval]DOUBLE*c);};//CCalculator的coclass对象[coclass,default(ICalculator),//组件的默认接口ICalculatorthreading(apartment),//组件线程模式,我们选择了apartmentvi_progid(Calculator.Calculator),progid(Calculator.Calculator.1),//组件Calculator的ProgIDversion(1.0),//组件Calculator的唯一ID,等价与后面的CLSID_CCalculatoruuid(D847DC60-2B09-4B9F-A9AC-F9DDCE7030F6),helpstring(CalculatorClass)]classATL_NO_VTABLECCalculator:publicICalculator//该类实现ICalculator接口{public:CCalculator(){}DECLARE_PROTECT_FINAL_CONSTRUCT()HRESULTFinalConstruct(){returnS_OK;}voidFinalRelease(){}public:STDMETHOD(Add)(DOUBLEa,DOUBLEb,DOUBLE*c);};在CalculatorX.CPP文件中会添加如下代码:STDMETHODIMPCCalculator::Add(DOUBLEa,DOUBLEb,DOUBLE*c){//TODO:在此添加实现代
本文标题:组件技术培训教程
链接地址:https://www.777doc.com/doc-985095 .html