Delphi下的COM编程

2008-04-09 04:19:58来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折


Delphi下的COM编程

作者:岑心 03/9(转载需征得作者同意)


Delphi通过向导可以非常迅速和方便的直接建立实现COM对象的代码,但是整个COM实现的过程被完全的封装,甚至没有VCL那么结构清晰可见。

一个没有C 下COM开发经验甚至没有接触过COM开发的Delphi程序员,也能够很容易的按照教程设计一个接口,但是,恐怕深入一想,连生成的

代码代表何种意义,哪些能够定制都不清楚。前几期 “DELPHI下的COM编程技术”一文已经初步介绍了COM的一些基本概念,我则想谈一些个人

的理解,希望能给对Delphi下COM编程有疑惑的朋友带来帮助。

COM (组件对象模型 Component Object Model)是一个很庞大的体系。简单来说,COM定义了一组API与一个二进制的标准,让来自不同平台、不

同开发语言的独立对象之间进行通信。COM对象只有方法和属性,并包含一个或多个接口。这些接口实现了COM对象的功能,通过调用注册的COM

对象的接口,能够在不同平台间传递数据。

COM光标准和细节就可以出几本大书。这里避重就轻,仅仅初步的解释Delphi如何进行COM的封装及实现。对于上述COM技术经验不足的Delphi程

序开发者来说,Delphi通过模版生成的代码就像是给你一幅抽象画照着画一样,画出来了却不一定知道画的究竟是什么,也不知该如何下手画

自己的东西。本文能够帮助你解决这类疑惑。

再次讲解一些概念

“DELPHI下的COM编程技术”一文已经介绍了不少COM的概念,比如GUID、CLSID、IID,引用计数,IUnKnown接口等,下面再补充一些相关内容

COM与DCOM、COM 、OLE、ActiveX的关系

DCOM(分布式COM)提供一种网络上访问其他机器的手段,是COM的网络化扩展,可以远程创建及调用。COM 是Microsoft对COM进行了重要的更

新后推出的技术,但它不简单等于COM的升级,COM 是向后兼容的,但在某些程度上具有和COM不同的特性,比如无状态的、事务控制、安全控

制等等。

以前的OLE是用来描述建立在COM体系结构基础上的一整套技术,现在OLE仅仅是指与对象连接及嵌入有关的技术;ActiveX则用来描述建立在COM

基础上的非COM技术,它的重要内容是自动化(Automation),自动化允许一个应用程序(称为自动化控制器)操纵另一个应用程序或库(称为

自动化服务器)的对象,或者把应用程序元素暴露出来。

由此可见COM与以上的几种技术的关系,并且它们都是为了让对象能够跨开发工具跨平台甚至跨网络的被使用。


Delphi下的接口

Delphi中的接口概念类似C 中的纯虚类,又由于Delphi的类是单继承模式(C 是多继承的),即一个类只能有一个父类。接口在某种程度上

可以实现多继承。接口类的声明与一般类声明的不同是,它可以象多重继承那样,类名 = class (接口类1,接口类2… ),然后被声明的接口

类则重载继承类的虚方法,来实现接口的功能。

以下是IInterface、IUnknown、IDispatch的声明,大家看出这几个重要接口之间是什么样的联系了吗?任何一个COM对象的接口,最终都是从

IUnknown继承的,而Automation对象,则还要包含IDispatch,后面DCOM部分我们会看到它的作用。

IInterface = interface

[''''{00000000-0000-0000-C000-000000000046}'''']

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

function _AddRef: Integer; stdcall;

function _Release: Integer; stdcall;

end;

IUnknown = IInterface;

IDispatch = interface(IUnknown)

[''''{00020400-0000-0000-C000-000000000046}'''']

function GetTypeInfoCount(out Count: Integer): HResult; stdcall;

function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;

function GetIDsOfNames(const IID: TGUID; Names: Pointer;

NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;

function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;

Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;

end;

对照“DELPHI下的COM编程技术”一文,可以明白IInterface中的定义,即接口查询及引用记数,这也是访问和调用一个接口所必须的。

QueryInterface可以得到接口句柄,而AddRef与Release则负责登记调用次数。

COM和接口的关系又是什么呢?COM通过接口进行组件、应用程序、客户和服务器之间的通信。COM对象需要注册,而一个GUID则是作为识别接口

的唯一名字。

假如你创建了一个COM对象,它的声明类似 Txxxx= class(TComObject, Ixxxx),前面是COM对象的基类,后面这个接口的声明则是:Ixxxx =

interface(IUnknown)。所以说IUnknown是Delphi中COM对象接口类的祖先。到这一步,我想大家对接口类的来历已经有初步了解了。


聚合

接口是COM实现的基础,接口也是可继承的,但是接口并没有实现自己,仅仅只有声明。那么怎么使COM对象对接口的实现得到重用呢?答案就

是聚合。聚合就是一个包含对象(外部对象)创建一个被包含对象(内部对象),这样内部对象的接口就暴露给外部对象。

简单来说,COM对象被注册后,可以找到并调用接口。但接口不是仅仅有个定义吗,它必然通过某种方式找到这个定义的实现,即接口的“实现

类”的方法,这样才最终通过外部的接口转入进行具体的操作,并通过接口返回执行结果。


进程内与进程外(In-Process, Out-Process)

进程内的接口的实现基础是一个DLL,进程外的接口则是建立在应用程序(EXE)上的。通常我们建立进程外接口的目的主要是为了方便调试(

跟踪DLL是件很麻烦的事),然后在将代码改为进程内发布。因为进程内比进程外的执行效率会高一些。

COM对象创建在服务器的进程空间。如果是EXE型服务器,那么服务器和客户端不在同一进程;如果是DLL型服务器,则服务器和客户端就是一个

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:如何按照分割符分离一行文字

下一篇:監視資源管理器的文件變化