荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Deny (单调但不乏味——我的生活), 信区: Program
标  题: 我们的梦想 用COM重造我们的软件
发信站: 荔园晨风BBS站 (Fri Oct 19 20:20:59 2001), 转信

关键词:

COM OLE ACTIVE X CONTAINER AUTOMATION CONTROLE Iunknown IDispatch
SELF_CONTAINED CLASS FACTORY DCOM COM+ MTS MSMQ


概 论


一个应用程序通常是由一个二进制文件组成。当编译器生成此文件后,在对下一版
本重新编译并发行新生成的版本值之前,应用程序一般不会发生任何变化。操作系
统、硬件及客户需求的改变都必须等到整个应用程序被重新编译后才能够得以认可
。整个软件业就是这样随着已发行软件的日益“老化”而奔向未来的。目前,这种
状况已经发生了变化。开发人员找到的一种方案是将单个的应用程序分割成多个独
立的部分。即组件。也就是将软部件看成对象。

这种做法的好处是可以随技术的不断发展而用新的组件取代已有的组件。此时的应
用程序将不再是以前那样是一个在发行前就已注定过时的实体,而是可以随着新组
件不断取代就组件而趋于完善。


这一点对我们来说并没有太大的诱惑力。谁都知道我们不可能天天给用户发行新的
版本。

但有一点你一定喜欢,当你根据需要更改了DLL中的一些实现函数,生成了DLL后,不
需要重新编译整个程序,就能使用新的性能。是不是有些不可思议。


使用COM模型给软件带来的影响将是巨大的。是软件工业的革命。对于一个软件的
编程者,谁不想在编程中能够使用像MFC那样方便的使用类,而不是面对枯燥而又
嵌得很深的函数,使人眼花缭乱全局变量。在改动程序前花费大量的时间去理解源
程序。COM提供了一种二进制标准的、面向对象、可扩充、可重用的通讯协议。如
果你继续读下去,就会发现构建基于COM的测量软件给你带来的好处将是巨大的。
花点时间、金钱将得到事半功倍的回报。




每个程序员恐怕都有这样的经历:当修改一个大型程序时,由于程序本身结构的复
杂性,使某些功能的实现难度非常大。怎样才能构造出一个逻辑清晰、结构完整、
功能相对独立、便于扩充的逻辑模型?MICROSOFT提供了COM,APPLE有它的
OPENDOC,IBM有SOM。现在的软件业正在走着二十年前硬件所走过的道路。二十年
前,人们制造了集成电路块,用一块块能完成特定工作的小芯片,构造新的更大的
芯片,去完成新的功能。这就是软件业所面临的问题。当今计算机界最热门的两项
新技术是COM和DCOM。COM似乎成为了解决所有软件开发弊端的良方。当然这不意味
着使用COM后你将一劳永逸。软件业是没有”银弹”神话的。只不过COM对我们今天
面临的新问题有了更好的解决方案。例如分布式程序的开发,事务处理的安全,跨
平台的可重用性------

使用组件的优点:

使用组件的优点是应用程序可随时间的流逝而发展进化。除此之外,使用组件可是
对已有应用程序的升级更方便和灵活。组件构架从本质上讲是可定制的,用户可以
用更能满足他们需要的组件来将某个组件替换掉。象类一样,COM是一个软件编程的
构造模型,而不是一个数学模型。








一 组件技术的演变


观察组件技术的演变是理解COM和DCOM的开始,虽然面向对象技术已经经历了一个
完整的自身演变的过程,但组件技术作为面向对象技术的一个派生物,却有着自己
的演变过程。组件技术的演变的主要根基是WINDOWS OS。当然,其他的一些技术也
起了很大的作用。

1.在WINDOWS 3.0中出现的定制控制(CUSTOM CONTROL)。一个定制控制就是一个
可以输出定义好的函数集合的动态链接库。但与一般的DLL 不同的是,一个定制控
制能进行特性操作,并能处理由用户或程序输入所引起的触发事件。

2.1991年MICROSOFT推出的VBX,使小型的可重用组件的重要作用体现得淋漓尽致
。但遗憾的是,VBX软件包内约束太多,16位的结构,且没有一个开放的接口,限
制了VBX的应用。

3.也就是同一年MICROSOF开发了OLE1.0规范。(OBJECT LINKING AND
EMBEDDING )。OLE1.0努力朝着文件中心的方向发展,而不是传统的以应用为中心
的发展方向。“复合文档”是这个思想的产物,是在单个文件中以文本、图形、视
频、图形和声音等多种格式存储数据的方法。office套件中的word我们是再熟悉不
过了。但ole1.0由于自身的复杂性,及实现的技术方面的不成熟。在市场上遭到了
冷遇。

4.Microsoft 并没被ole1.0的困难所吓倒,而是继续致力于ole的改进与提高。
1993年发布了ole2.0规范,推出了一个完全基于对象的服务结构,易于扩展、定制
和增强。通过这种结构可得到的服务是:

Com

剪贴板(clipboard)

拖放(drag and drop)

嵌入(embedding)

定点激活(in-place activation)

链接(linking)

标记(永久命名)(moniker(persistent naming))

ole自动化(ole automation)

ole控制(ole control)

ole文档(ole document)

结构化存储(structrued storage)

同一数据传输(uniform data transfer,UDT)


5.ACTIVE X


1996年3月INTERNET专业开发人员研讨会(Internet PDC)上提出ACTIVE X一词,当初
仅做为一种号召而非具体的应用程序开发技术。称为:Active the Internet随着
INTERNET的飞速发展,Active X成为定义从Web页面到OLE控件的所有内容的核心。
一方面,它代表了将用户联到MICROSOFT,INTERNET和业界的新技术的小型快速得
重用组件。另一方面:ACTIVE X代表着INTERNET与应用程序集成的策略.

有一种说法:“ACTIVE X是OLE 与INTERNET碰撞的产物,INTERNET使它变成了今天
的样子".


今天的ACTIVE X包括:

ACTIVE X 文档

ACTIVE X 控件

COM

INTERNET标记

Active X超级链接

Active x会议

Active X服务器扩展

Active X脚本

代码签名

HTML扩展

活动电影




二 初探COM


组件对象模型(简称COM)是windows对象的二进制标准。为WINDOWS提供了统一的,
面向对象的,可扩充的通讯协议。这意味着描述一个对象的可执行代码(.dll 或
.exe 文件的代码)可以被其它对象执行。即使两个对象使用不同语言来编写的,他
们可以用COM标准来进行通信。




个人认为:COM是MICROSOFT发展的产物,日前MICROSOFT所提出的大部分概念都是基
于COM的。COM随着MICROSOFT的壮大而不断完善,MICROSOFT也为COM引以为豪。如今
MICROSOFT 产品已发展成为一个软件大家族。 OFFICE系列、VISUAL BASIC、
VISUAL C++、VISUAL J++都已成为WINDOWS程序设计的标准,为了在不同应用程序之
间进行数据交换,达到资源共享的目的,迫切需要一种接口规则与协议。建立一个
软件模块同另一个软件模块的连接,然后将其描述出来,当这种连接建立起来后,
两个模块之间就可以通过成为接口的机制来进行通讯。COM立足于二进制这一层,是
语言无关的接口规范。


曾经使用的数据交换技术存在的问题:

*WINDOWS API有太大的编程“接口面”(超过350个单独函数)

*VBA 不能在WIN32环境中使用

*DDE 是一个关于应用程序,主题和项目的复杂系统。

*DLL 是完全面向应用程序的




COM的特征在于:

*为WIN32客户EXE载入和调用WIN32 DLL提供了一种标准的与语言无关的方法。

*为一个EXE控件同一机器的另一个EXE提供了通用的方法。(可代替DDE)

*用ACTIVE X代替了VBX。

*为应用程序与操作系统的交互操作提供了一种新的方法。

*为适应新的协议提供了可扩充性,如MICROSOFT的OLE DB数据接口。

*分步式COM(DCOM)允许一个EXE与不同及其上的另一个EXE进行通讯。

*COM+则综合了COM、DCOM、MTS和MSMQ。


1.COM的基本设计思路:

通常我们描述一个对象是将其划分若干的方法和属性。通过继承这一机制来获取对
方法使用和属性访问的权利,以达到数据处理的目的。而COM模块不再允许客户直
接调用对象的方法(包括属性及其构造函数,析构函数),COM只提供一个标准的
全局函数来访问对象。从而最大限度的将客户与服务分离。 在客户与服务器之间
通过接口来连结,使用虚拟函数表(vtbl)的内存结构,实现了一组指向虚拟函数
实现的指针。


2.COM如何进行数据交换?

通过接口。

这个接口定义了函数调用方法,标准的基于结构的数据传输技术,以及一些标准的函
数调用。接口是虚函数的集合,实质上是函数名的集合。它是没有数据的 C++类 。
 是纯的虚函数,对象从这个类继承,并提供函数代码,其他函数通过调用这些函数来
获得代码,所有组件对象必须有一个称为IUnknow 的接口。

IUnknown接口的目的:找到其他的接口。它有一个QueryInterface()函数,该函数使
用一个接口ID,返回一个指向该对象接口的指针。所有其它接口都从IUnknown中继
承,因此,所用接口中都有Query Interface()。






interface IUnknown{

public:

BEGIN_INTERFACE

virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,

void_RPC_FAR *_RPC_FAR *ppvObject)=0;

virtual ULONG STDMETHODCALLTYPE AddRef(void)=0;

virtual ULONG STDMETHODCALLTYPE Release(void)=0;

END_INTERFACE};


其中AddRef() 和Release()用来跟中那些正在使用接口的应用程序.

所有三个函数被所有接口继承.





接口的实现:

可以通过多重继承。但多重继承遇到的问题是:当多个接口方法符号名冲突的问题
。即多个接口都含有同名的方法,而不同接口的方法实现各不相同。编译器仅允许
程序员提供一个方法的实现。显然通过多重继承来实现接口是有问题的。

而在MFC中,通过类嵌套来实现。MFC库有一组宏可以自动实现这个过程。

INTERFACE_PART宏产生嵌套类,并为特定的接口函数产生原型,并加上
QueryInterface,AddRef和Release的原型。

DECLARE_INTERFACE_MAP宏产生一张表的声明,该表包含了所有类接口的ID。
CCmdTarget::ExternalQueryInterface( )函数使用该表来获取接口指针。








3.另一个有用的接口��类厂(CLASS FACTORY)

CLASS FACTORY是一种类,是被用来支持名为IClassFactory的特殊的COM接口。
IClassFactory是从IUnknown派生的,它的主要成员函数是:CreateInstance()
,它产生的原因是在COM中我们无法直接调用构造函数,于是只好让组件来决定如
何构造对象,为此组件提供了类厂,从而将具体的创建过程封装起来。利用类厂来
创建多个对象。MFC库采取动态创建技术来解决这一问题,一个名为
COleObjectFactory的类可以在运行时创建任何类。采用DYNCREATE宏设置标准的动
态创建机制。OLECREATE宏声明和定义了一个COleObjectFactory类的全局对象,使
用指定的唯一CLSID。在DLL组件中,倒出函数DllGetClassObject根据OLECREATE宏
设置的全局变量,找到特定的类厂对象,并返回指向该对象的指针。当DLL被初始
化时,RegesterAll被调用,在EXE组件中,初始化代码调用静态的
COleObjectFactory::RegisterAll函数,该函数查找所有的厂对象,并调用
CoRegisterClassObject注册每一个对象。


接口集、接口、接口函数、属性之间的关系。

个人认为:接口集、接口、接口函数(方法)、属性在逻辑上存在着一定的对应的
关系。接口集包含多个接口。一个接口包含着一类接口函数,每一接口函数对应着
一类属性。接口函数才是用户所关心的,用户只有通过接口使用接口函数才能改变
属性。属性与接口函数都是对组件对象的抽象。




4.AUTOMATION & ACTIVE X

AUTOMATION & ACTIVE X是ACTIVE X组件的重要部分。ACTIVE X控件也是小型的
AUTOMATION服务器。AUTOMATION让应用程序告诉它做什么。它揭示属性和方法。如
果我们揭示了自己应用程序的所有方法和属性,则使用AUTOMATION应用程序的任何
编程语言都能成为自己应用程序的书写语言。知道有关与AUTOMATION交互的最主要
的事情总有一个程序在控制着。控制着的应用程序称AUTOMATION控制器,揭示方法
和属性的应用程序称为AUTOMATION服务器。


AUTOMATION通讯实际上已经明确定义了主从关系。主是自动化客户程序,从是自动
化组件(控件)。通过构造一个组件对象,或者与已经运行的程序中的现存对象建
立连接,客户程序可以对相互作用过程进行初始化,然后客户程序可以调用组件程
序中的接口函数,并且将那些已完成的接口释放掉。


这意味着WORD ,EXCEL,ACCESS及VB这些支持AUTOMATION的应用程序,可以被连接
到与AUTOMATION兼容的组件中。我们用VC++就可以调用WINDOWS下的任何控件(即
使它包含在WORD 或其他程序中),也可以用VC++自己编写组件,而用VBA宏来对它
进行调用。




(1)IDispatch是自动化的核心。它将所有的内部模块通讯都汇集在IDispatch::
Invoke()上,像IUnknown和IClassFactory一样,它完全被COM调度(
marshaling)所支持。从组件一方面来看,我们需要有一个具有IDispatch接口(
包含必要的类厂)的COM类;从用户方面来看,我们使用标准的COM技术来获取指针


interface IDispatch:public IUnknown

{

public:

virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(

UINT iTInfo,

LCID lcid,

ITypeInfo _RPC_FAR *_RPC_FAR *ppTInfo)=0;

virtual HRESULT STDMETHODCALLTYPE GetIDsofNames(

REFIID riid,

LPOLESTR _RPC_FAR *rgszNames,

LCID lcid,

DISPID _RPC_FAR *rgDispId)=0;

virtual HRESULT STDMETHODCALLTYPE Invoke(

DISPID dispIdMember,

REFIID riid,

LCID lcid,

WORD wFlag,

DISPPARAMS _RPC_FAR *pDispParams,

VARIANT _RPC_FAR *pVarResult,

EXCEPINFO _RPC_FAR *pExcepInfo,

UINT _RPC_FAR *puaArgErr)=0;


};


说明:Invoke()函数是其中最主要的函数,用于调用AUTOMATION服务器的函数和
属性。


(2)IDispatch 的实现:

组件程序可以有几种方法来实现IDispatch接口。最通常的做法是把大部分工作交
给WINDOWS的COM DLL,这可以通过调用COM函数CreateStdDispatch来实现,或把
Invoke调用委托给ITypeInfo接口,由它来处理组件的类型库(type library)。
一个类型库是一张表,该表允许客户查找组件中的对象方法和属性的符号化名字。
MFC支持类型库,但在IDispatch的实现中并没有用到类型库。IDispatch的实现是
靠分发映射(DISPATCH MAP)驱动的。MFC程序根本不调用CreateStdDispatch,它
也不用类型库来实现IDispatch::GetIDsOfName。


(3)MFC 的分发映射是如何与IDispatch和 Invoke成员函数相关连?

分发映射宏在内部产生了一个数据表,MFC中的Invoke函数可以读到该表。 控制程
序可以得到类的IDispatch指针。并且用一个指针数组作为参数调用Invoke。MFC的
Invoke函数的执行体会利用类分发映射对所提供的指针进行解码,可以调用某个成
员函数。



(4)关于VARIANT类型:

自动化客户和组件都用到了VARIANT类型。它是一个通用数据类型,是64位数据。
IDspatch::Invoke利用它来传递参数和返回值。

BEGIN_DISPATCH_MAP(CWwddCtrl, COleControl)

//{{AFX_DISPATCH_MAP(CWwddCtrl)

DISP_PROPERTY_NOTIFY(CWwddCtrl, "Wdlowline", m_wdlowline,
OnWdlowlineChanged, VT_R4)

DISP_PROPERTY_NOTIFY(CWwddCtrl, "Wdcaption", m_wdcaption,
OnWdcaptionChanged, VT_BSTR)

DISP_PROPERTY_NOTIFY(CWwddCtrl, "Wdxmean", m_wdxmean, OnWdxmeanChanged,
 VT_BSTR)

DISP_PROPERTY_NOTIFY(CWwddCtrl, "Wdymean", m_wdymean, OnWdymeanChanged,
 VT_BSTR)

DISP_FUNCTION(CWwddCtrl, "setwdobject", setwdobject, VT_EMPTY, VTS_I4)

DISP_FUNCTION(CWwddCtrl, "setwdproper", setwdproper, VT_EMPTY, VTS_I4)

DISP_FUNCTION(CWwddCtrl, "deletelist", deletelist, VT_EMPTY, VTS_NONE)

DISP_FUNCTION(CWwddCtrl, "addwdvalue", addwdvalue, VT_EMPTY, VTS_R4)

DISP_FUNCTION(CWwddCtrl, "setambie", setambie, VT_EMPTY, VTS_R4 VTS_R4
VTS_R4)

END_DISPATCH_MAP()








2.Active X控件


一个典型的空间包括设计时和运行时的用户界面,唯一的IDispatch接口定义控件的
方法和属性,唯一的IConnectionPoint接口用于控件可引发的事件。除此之外,一
个控件还可以包含对其整个生命周期的一执性支持,以及对剪贴,拖放等用户界面
特性的支持。从结构上看,一个控件有大量必须支持的COM接口,以利用这些特性
。Active X控件永远是放在其所放置的容器内运行的,空间的扩展名为.OCX,但从
运行模块的角度看,它不过是一个标准的WINDOWS DLL文件。


属性和事件是容器内应用程序与控件通讯的方式,容器和控件之间的通信使用事件
。对于Active X控件,事件是在容器端时显现的IDispatch接口。事件的底层机制
称连接点。一个连接点就是与容器通讯所需接口的类型描述,连接点不只限于
IDispatch接口,它也可用任何COM实现,控件只不过第一个利用他们。

ACTIVE X 是一个独立的对象,可以激起和相应事件,处理消息,具有唯一的属性,并
有多线程能力,并支持其余容器之间的双向通信和消息传递.ACTIVE X控件最奇妙的
地方在于它的可编程性和克重复使用性.它对外部环境是开放的,能被各种编程合肥
编程环境使用.控件对外有三个属性集.(属性,对象,方法)

--

         .-. .-.                        ?
        (   `   )     □    悄悄地把心锁起来,藏在你不知道的地方    □
         `.   .'      □    等到你来的那一天,我让你的心不再空白    □
           `.'


※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.201]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店