《Delphi下的COM编程介绍》由会员分享,可在线阅读,更多相关《Delphi下的COM编程介绍(11页珍藏版)》请在金锄头文库上搜索。
1、Delphi 下的下的 COM 编程介绍编程介绍 Delphi 通过向导可以非常迅速和方便的直接建立实现 COM 对象的代码, 但是整个 COM 实现的过程被完全的封装,甚至没有 VCL 那么结构清晰可见。 一个没有 C+下 COM 开发经验甚至没有接触过 COM 开发的 Delphi 程序员,也能够很容易的按照教程设计一个接口,但是,恐怕深入一想,连生成的代码代表何种意义,哪些能够定制都不清楚。前几期 “DELPHI 下的 COM编程技术”一文已经初步介绍了 COM 的一些基本概念,我则想谈一些个人的理解, 希望能给对 Delphi 下 COM 编程有疑惑的朋友带来帮助。 COM (组件对象
2、模型 Component Object Model)是一个很庞大的体系。简单来说,COM 定义了一组 API 与一个二进制的标准,让来自不同平台、不同开发语言的独立对象之间进行通信。COM 对象只有方法和属性,并包含一个或多个接口。这些接口实现了 COM 对象的功能,通过调用注册的 COM 对象的接口,能够在不同平台间传递数据。 COM 光标准和细节就可以出几本大书。这里避重就轻,仅仅初步的解释 Delphi 如何进行 COM 的封装及实现。对于上述 COM 技术经验不足的 Delphi 程序开发者来说,Delphi 通过模版生成的代码就像是给你一幅抽象画照着画一样,画出来了却不一定知道画的究
3、竟是什么,也不知该如何下手画自己的东西。本文能够帮助你解决这类疑惑。 再次讲解一些概念再次讲解一些概念 “DELPHI 下的 COM 编程技术”一文已经介绍了不少 COM 的概念,比如 GUID、CLSID、IID,引用计数,IUnKnown 接口等,下面再补充一些相关内容: COM 与与 DCOM、COM+、OLE、ActiveX 的关系的关系 DCOM(分布式 COM)提供一种网络上访问其他机器的手段,是 COM 的网络化扩展,可以远程创建及调用。COM+是 Microsoft 对 COM 进行了重要的更新后推出的技术,但它不简单等于 COM 的升级,COM+是向后兼容的,但在某些程度上具
4、有和 COM 不同的特性,比如无状态的、事务控制、安全控制等等。 以前的 OLE 是用来描述建立在 COM 体系结构基础上的一整套技术,现在 OLE 仅仅是指与对象连接及嵌入有关的技术;ActiveX 则用来描述建立在 COM 基础上的非 COM 技术,它的重要内容是自动化(Automation),自动化允许一个应用程序(称为自动化控制器)操纵另一个应用程序或库(称为自动化服务器)的对象,或者把应用程序元素暴露出来。 由此可见 COM 与以上的几种技术的关系, 并且它们都是为了让对象能够跨开发工具跨平台甚至跨网络的被使用。 Delphi 下的接口下的接口 Delphi 中的接口概念类似 C+中
5、的纯虚类,又由于 Delphi 的类是单继承模式(C+是多继承的),即一个类只能有一个父类。接口在某种程度上可以实现多继承。接口类的声明与一般类声明的不同是,它可以象多重继承那样,类名 = class (接口类 1,接口类 2 ),然后被声明的接口类则重载继承类的虚方法,来实现接口的功能。 以下是 IInterface、IUnknown、IDispatch 的声明,大家看出这几个重要接口之间是什么样的联系了吗?任何一个 COM 对象的接口, 最终都是从 IUnknown 继承的, 而 Automation 对象, 则还要包含 IDispatch, 后面 DCOM部分我们会看到它的作用。 IIn
6、terface = 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- 00000000
7、0046 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: In
8、teger; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; end; 对照“DELPHI 下的 COM 编程技术”一文,可以明白 IInterface 中的定义,即接口查询及引用记数,这也是访问和调用一个接口所必须的。 QueryInterface 可以得到接口句柄,而 AddRef 与 Release 则负责登记调用次数。 COM 和接口的关系又是什么呢?COM 通过接口进行组件、应用程序、客户和服务
9、器之间的通信。COM 对象需要注册,而一个 GUID 则是作为识别接口的唯一名字。 假如你创建了一个 COM 对象,它的声明类似 Txxxx= class(TComObject, Ixxxx),前面是 COM 对象的基类,后面这个接口的声明则是:Ixxxx = interface(IUnknown)。所以说 IUnknown 是 Delphi 中 COM 对象接口类的祖先。到这一步,我想大家对接口类的来历已经有初步了解了。 聚合聚合 接口是 COM 实现的基础,接口也是可继承的,但是接口并没有实现自己,仅仅只有声明。那么怎么使 COM 对象对接口的实现得到重用呢?答案就是聚合。 聚合就是一个包
10、含对象 (外部对象) 创建一个被包含对象 (内部对象) ,这样内部对象的接口就暴露给外部对象。 简单来说,COM 对象被注册后,可以找到并调用接口。但接口不是仅仅有个定义吗,它必然通过某种方式找到这个定义的实现,即接口的“实现类”的方法,这样才最终通过外部的接口转入进行具体的操作,并通过接口返回执行结果。 进程内与进程外(进程内与进程外(In- Process, Out- Process) 进程内的接口的实现基础是一个 DLL,进程外的接口则是建立在应用程序(EXE)上的。通常我们建立进程外接口的目的主要是为了方便调试(跟踪 DLL 是件很麻烦的事),然后在将代码改为进程内发布。因为进程内比进
11、程外的执行效率会高一些。 COM 对象创建在服务器的进程空间。如果是 EXE 型服务器,那么服务器和客户端不在同一进程;如果是 DLL型服务器,则服务器和客户端就是一个进程。所以进程内还能节省内存空间,并且减少创建实例的时间。 StdCall 与与 SafeCall Delphi 生成的 COM 接口默认的方法函数调用方式是 stdcall 而不是缺省的 Register。 这是为了保证不同语言编译器的接口兼容。 双重接口(在后面讲解自动化时会提到双重接口)中则默认的是 SafeCall。它的意义除了按 SafeCall 约定方式调用外,还将封装方法以便向调用者返回 HResult 值。Saf
12、eCall 的好处是能够捕获所有异常,即使是方法中未被代码处理的异常,也可以被外套处理并通过 HResult 返回给调用者。 WideString 等一些有差异的类型 接口定义中缺省的字符参数或返回值将不再是 String 而是 WideString。WideString 是 Delphi 中符合 OLE 32- bit 版本的 Unicode 类型,当是字符时,WideString 与 String 几乎等同,当处理 Unicode 字符时,则会有很大的差别。联想到 COM 本身是为了跨平台使用,可以很容易的理解为什么数据通信时需要使用 WideString 类型。 同样的道理,intege
13、r 类型将变成 SYSINT 或者 Int64、SmallInt 或者 Shortint,这些细微的变化都是为了符合规范。 通过向导生成基础代码通过向导生成基础代码 打开创建新工程向导(菜单“File- New- Other”或“New Items 按钮”),选择 ActiveX 页。先建立一个 ActiveX Library。编译后即是个 DLL 文件(进程内)。然后在同样的页面再建立一个 COM Object。 实例模式与线程模式实例模式与线程模式 接着你将看到如下向导,除了填写类名外(接口名会自动根据类名填充),还有实例创建方式(Instancing)和线程模式(Threading Mo
14、del)的选项。 实例模式决定客户端请求后,COM 对象如何创建实例: Internal:供 COM 对象内部使用,不会响应客户端请求,只能通过 COM 对象内部的其他方法来建立; Single Instance:不论当前系统内部是否存在相同 COM 对象,都会建立一个新的程序及独立的对象实例; Mulitple Instance:如果有多个相同的 COM 对象,只会建立一个程序,多个 COM 对象的实例共享公共代码,并拥有自己的数据空间。 Single/ Mulitple Instance 有各自的优点,Mulitple 虽然节省了内存但更加费时。即 Single 模式需要更多的内存资源,而
15、 Mulitple 模式需要更多的 CPU 资源,且 Single 的实例响应请求的负荷较为平均。该参数应根据服务器的实际需求来考虑。 线程模式线程模式有五种: Single:仅单线程,处理简单,吞吐量最低; Apartment:COM 程序多线程,COM 对象处理请求单线程; Free:一个 COM 对象的多个实例可以同时运行。吞吐量提高的同时,也要求对 COM 对象进行必要的保护,以避免多个实例冲突; Both:同时支持 Aartment 和 Free 两种线程模式。 Neutral:只能在 COM+下使用。 虽然 Free 和 Both 的效率得到提高,但是要求较高的技巧以避免冲突(这是
16、很不容易调试的),所以一般建议使用Delphi 的缺省方式。 类型库编辑器(类型库编辑器(Type Library) 假设我们建立一个叫做 TSample 的类和 ISample 的接口(如图),然后使用类型库编辑器创建一个方法GetCOMInfo(在右边树部分点击右键弹出菜单选择 New- Method 或者点击上方按钮),并于左边 Parameters页面建立两个参数(ValInt : Integer , ValStr : String),返回值为 BSTR。 除了常用类型外, 参数和返回值还可以支持很多指针、 OLE 对象、 接口类型。 建立普通的 COM 对象, 其 Returen T
17、ype 是可以任意的,这是和 DCOM 的一个区别。 双击 Modifier 列弹出窗口, 可以选择参数的方式: in、 out 分别对应 const、 out 定义, 选择 Has Default Value可设置参数缺省值。 Delphi 生成代码详解生成代码详解 点击刷新按钮刷新后,上面类型库编辑器对应的 Delphi 自动生成的代码如下: unit uCOM; $WARN SYMBOL_PLATFORM OFF interface uses Windows, ActiveX, Classes, ComObj, pCOM_TLB, StdVcl; type TSample = class
18、(TTypedComObject, ISample) protected function GetCOMInfo(ValInt: SYSINT; const ValStr: WideString): WideString; stdcall; end; implementation uses ComServ; function TSample.GetCOMInfo(ValInt: SYSINT;const ValStr: WideString): WideString; begin end; initialization TTypedComObjectFactory.Create(ComServ
19、er, TSample, Class_Sample, ciMultiInstance, tmApartment); end. 引用单元 有三个特殊的单元被引用:ComObj,ComServ 和 pCOM_TLB。ComObj 里定义了 COM 接口类的父类TTypedComObject 和类工厂类 TTypedComObjectFactory (分别从 TComObject 和 TComObjectFactory 继承, 早期版本如 Delphi4 建立的 COM, 就直接从 TcomObject 继承和使用 TComObjectFactory 了) ; ComServ单元里面定义了全局变量
20、ComServer: TComServer, 它是从 TComServerObject 继承的, 关于这个变量的作用,后面将会提到。 这几个类都是 delphi 实现 COM 对象的比较基础的类,TComObject(COM 对象类)和 TComObjectFactory(COM 对象类工厂类)本身就是 IUnknown 的两个实现类,包含了一个 COM 对象的建立、查询、登记、注册等方面的代码。TComServerObject 则用来注册一个 COM 对象的服务信息。 接口定义说明 再看接口类定义 TSample = class(TTypedComObject, ISample)。到这里,已
21、经可以通过涉及的父类的作用大致猜测到 TSample 是如何创建并注册为一个标准的 COM 对象的了。那么接口 ISample 又是怎么来的呢?pCOM_TLB 单元是系统自动建立的,其名称加上了_TLB,它里面包含了 ISample = interface(IUnknown)的接口定义。前面提到过,所有 COM 接口都是从 IUnknown 继承的。 在这个单元里我们还可以看到三种 ID (类型库 ID、 IID 及 COM 注册所必须的 CLSID) 的定义: LIBID_pCOM,IID_ISample 和 CLASS_Sample。关键是这时接口本身仅仅只有定义代码而没有任何的实现代码
22、,那接口创建又是在何处执行的?_TLB 单元里还有这样的代码: CoSample = class class function Create: ISample; class function CreateRemote(const MachineName: string): ISample; end; class function CoSample.Create: ISample; begin Result := CreateComObject(CLASS_Sample) as ISample; end; class function CoSample.CreateRemote(const Ma
23、chineName: string): ISample; begin Result := CreateRemoteComObject(MachineName, CLASS_Sample) as ISample; end; 由 Delphi 的向导和类型编辑器帮助生成的接口定义代码,都会绑定一个“Co+类名”的类,它实现了创建接口实例的代码。CreateComObject 和 CreateRemoteComObject 函数在 ComObj 单元定义,它们就是使用 CLSID创建 COM/DCOM 对象的函数! 初始化:注册 COM 对象的类工厂 类工厂负责接口类的统一管理实际上是由支持 ICl
24、assFactory 接口的对象来管理的。 类工厂类的继承关系如下: IClassFactory = interface(IUnknown) TComObjectFactory=class(TObject,IUnknown,IClassFactory,IClassFactory2) TTypedComObjectFactory = class(TComObjectFactory) 我们知道了接口 ISample 是怎样被创建的,接口实现类 TSample 又是如何被定义为 COM 对象的实现类。现在解释它是怎么被注册,以及何时创建的。这一切的小把戏都在最后 initialization 的部分
25、,这里有一条类工厂建立的语句。 Initialization 是 Delphi 用于初始化的特殊部分,此部分的代码将在整个程序启动的时候首先执行。回顾前面的内容并观察一下 TTypedComObjectFactory 的参数:ComServer 是用于注册/撤消注册 COM 服务的对象,TSample 是接口实现类, Class_Sample 是接口唯一对应的 GUID, ciMultiInstance 是实例模式, tmApartment是线程模式。一个 COM 对象应该具备的特征和要素都包含在了里面! 那么 COM 对象的管理又是怎么实现的呢?在 ComObj 单元里面可以见到一条定义 f
26、unction ComClassManager: TComClassManager; 这里 TComClassManager 顾名思义就是 COM 对象的管理类。任何一个祖先类为 TComObjectFactory 的对象被建立时,其 Create 里面会执行这样一句: ComClassManager.AddObjectFactory(Self); AddObjectFactory 方法的原形为 procedure TComClassManager.AddObjectFactory(Factory:ComObjectFactory); 相对应的还有 RemoveObjectFactory 方法
27、。 具体的代码我就不贴出来了, 相信大家已经猜测到了它的作用将当前对象(self)加入到 ComClassManager 管理的对象链(FFactoryList)中。 封装的秘密封装的秘密 读者应该还有最后一个疑问:假如服务器通过类工厂的注册以及 GUID 确定一个 COM 对象,那当客户端调用的时候,服务器是如何启动包含 COM 对象的程序的呢? 当你建立 ActiveX Library 的工程的时候,将发现一个和普通 DLL 模版不同的地方它定义了四个输出例程: exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, D
28、llUnregisterServer; 这四个例程并不是我们编写的,它们都在 ComServ 单元例实现。单元还定义了类 TComServer,并且在初始化部分创建了类的实例,即前面提到过的全局变量 ComServer。 例程DllGetClassObject通过CLSID得到支持IClassFactory接口的对象; 例程DllCanUnloadNow判断DLL是否可从内存卸载;DllRegisterServer 和 DllUnregisterServer 负责 DLL 的注册和解除注册,其具体的功能由ComServer 实现。 接口类的具体实现 好了, 现在自动生成代码的来龙去脉已经解释清
29、楚了, 下一步就是由我们来添加接口方法的实现代码。 在 function TSample.GetCOMInfo 的部分添加如下代码。我写的例子很简单,仅仅是根据传递的参数组织一条字符串并返回。以此证明接口正确调用并执行了该代码: function TSample.GetCOMInfo(ValInt: SYSINT;const ValStr: WideString): WideString; const Server1 = 1; Server2 = 2; Server3 = 3; var s : string; begin s := This is COM server : ; case Val
30、Int of Server1: s := s + Server1; Server2: s := s + Server2; Server3: s := s + Server3; end; s := s + #13 + #10 + Execute client is + ValStr; Result := s; end; 注册、创建注册、创建 COM 对象及调用接口对象及调用接口 随便建立一个 Application 用于测试上面的 COM。必要的代码很少,创建一个接口的实例然后执行它的方法。当然我们得先行注册 COM,否则调用根据 CLSID 找不接口的话,将报告“无法向注册表写入项”。如果接口
31、定义不一致,则会报告“Interface not supported”。 编译上面的这个 COM 工程,然后选择菜单“Run Register ActiveX Server”,或者通过 Windows 下system/system32 目录中的 regsvr32.exe 程序注册编译好的 DLL 文件。regsvr32 的具体参数可以通过regsvr32/?来获得。对于进程外(EXE 型)的 COM 对象,执行一次应用程序就注册了。 提示 DLL 注册成功后,就应该可以正确执行下列客户端程序了: uses ComObj, pCOM_TLB; procedure Ttest.Button1Cli
32、ck(Sender: TObject); var COMSvr : ISample; retStr : string; begin COMSvr := CreateComObject(CLASS_Sample) as ISample; if COMSvr nil then begin retStr := COMSvr.GetCOMInfo(2,client 2); showmessage(retStr); COMSvr := nil; end else showmessage(接口创建不成功); end; 最终值是从当前程序外的一个“接口”返回的,我们甚至可以不知道这个接口的实现!第一次接触
33、COM 的人,成功执行此程序并弹出对话框后,也许会体会到一种技术如斯奇妙的感觉,因为你仅仅调用了“接口”,就可以完成你猜测中的东西。 创建一个分布式创建一个分布式 DCOM(自动化接口)(自动化接口) IDispatch 在 delphi6 之前的版本中,所有接口的祖先都是 IUnknown,后来为了避免跨平台操作中接口概念的模糊,又引入了 IInterface 接口。 使用向导生成 DCOM 的步骤和 COM 几乎一致。而生成的代码仅将接口类的父类换为 TAutoObject,类工厂类换为 TAutoObjectFactory。这其实没有太大的不同,因为 TAutoObject 等于是一个标
34、准 COM 外加 IDispatch接口,而 TAutoObjectFactory 是从 TTypedComObjectFactory 直接继承的: TAutoObject = class(TTypedComObject, IDispatch) TAutoObjectFactory = class(TTypedComObjectFactory) 自动化服务器支持双重接口,而且必须实现 IDispatch。因讨论范畴限制,本文只能简单提出,IDispatch 是DCOM 和 COM 技术实现上的一个重要区别。 打开_TLB.pas 单元, 可以找到 Ixxx = interface(IDispa
35、tch)和 Ixxx = dispinterface 的定义,这在前面 COM 的例子里面是没有的。 创建过程中的差异创建过程中的差异 使用类型库编辑器的时候,有两处和 COM 不同的地方。首先 Return Type 必须选择 HRESULT,否则会提示错误,这是为了满足双重接口的需要。当 Return Type 选择 HRESULT 后,你会发现方法定义将变成 procedure(过程)而不是预想中的 function(函数)。 怎么才能让方法有返回值呢?还需要在 Parameters 最后多添加一个参数, 然后将该参数改名与方法名一致, 设置参数类型为指针(如果找不到某种类型的指针类型,
36、可以直接在类型后面加*,如图,BSTR*是 BSTR 的指针类型)。最后在 Modifier 列设置 Parameter Flags 为 RetVal,同时 Out 将被自动选中,而 In 将被取消。 刷新后,得到下列代码。添加方法的具体实现,大功告成: TSampleAuto = class(TAutoObject, ISampleAuto) protected function GetAutoSerInfo(ValInt: SYSINT;const ValStr: WideString): WideString; safecall; end; 远程接口调用远程接口调用 远程接口的调用需要使
37、用 CreateRemoteComObject 函数,其它如接口的声明等等与 COM 接口调用相同。CreateRemoteComObject 函数比 CreateComObject 多了一个参数,即服务器的计算机名称,这样就比 COM多出了远程调用的查询能力。前面“接口定义说明”一节的代码可以对照 CreateComObject、CreateRemoteComObject 的区别。 自定义自定义 COM 的对象的对象 接口一个重要的好处是:发布一个接口,可以不断更新其功能而不用升级客户端。因为不论应用升级还是业务改变,客户端的调用方式都是一致的。 既然我们已经弄清楚 Delphi 是怎样实现
38、一个接口的,那能否不使用向导,自己定义接口呢?这样做可以用一个接口继承出不同的接口实现类,来完成不同的功能。同时也方便了小组开发、客户端开发、进程内/外同步编译以及调试。 接口单元:接口单元:xxx_TLB.pas 前面略讲了接口的定义需要注意的方面。接口除了没有实例化外,它与普通类还有以下区别:接口中不能定义字段,所有属性的读写必须由方法实现;接口没有构造和析构函数,所有成员都是 public;接口内的方法不能定义为virtual,dynamic,abstract,override。 首先我们要建立一个接口。前面讲过接口的定义只存在于一个地方,即 xxx_TLB.pas 单元里面。使用类型库
39、编辑器可以产生这样一个单元。还是在新建项目的 ActiveX 页,选择最后一个图标(Type Library)打开类型库编辑器,按 F12 键就可以看到 TLB 文件(保存为.tlb)了。没有定义任何接口的时候,TLB 文件里除了一大段注释外只定义了 LIBID(类型库的 GUID)。假如关闭了类型库编辑器也没有关系,可以随时通过菜单 View Type Library打开它。 先建立一个新接口(使用向导的话这步已经自动完成了),然后如前面操作一样建立方法、属性生成的 TLB 文件内容与向导生成_TLB 单元大致相同,但仅有定义,缺乏“co+类名”之类的接口创建代码。 再观察代码, 将发现接口
40、是从 IDispatch 继承的, 必须将这里的 IDispatch 改为 IUnknown。 保存将会得到.tlb文件,而我们想要的是一个单元(.pas)文件,仅仅为了声明接口,所以把代码拷贝复制并保存到一个新的 Unit。 自定义自定义 CLSID 从注册和调用部分可以看出 CLSID 的重要作用。CLSID 是一个 GUID(全局唯一接口表示符),用来标识对象。GUID 是一个 16 个字节长的 128 位二进制数据。Delphi 声明一个 GUID 常量的语法是: Class_XXXXX : TGUID = xxxxxxxx- xxxxx- xxxxx- xxxxx- xxxxxxxx
41、; 在 Delphi 的编辑界面按 Ctrl+Shift+G 键可以自动生成等号后的数据串。 GUID 的声明并不一定在_TLB 单元里面,任何地方都可以声明并引用它。 接口类声明与实现接口类声明与实现 新建一个 ActiveX Library 工程,加入刚才定义的 TLB 单元,再新建一个 Unit。我的 TLB 单元取名为MyDef_TLB.pas,定义了一个接口 IMyInterface = interface(IUnknown),以及一个方法 function SampleMethod(val: Smallint): SYSINT; safecall;现在让我们看看全部接口类声明及实现
42、的代码: unit uMyDefCOM; interface uses ComObj, Comserv, ActiveX, MyDef_TLB; const Class_MySvr : TGUID = 1C0E5D5A- B824- 44A4- AF6C- 478363581D43; type TMyIClass = class(TComObject, IMyInterface) procedure Initialize; override; destructor Destroy; override; private FInitVal : word; public function Sampl
43、eMethod(val: Smallint): SYSINT; safecall; end; TMySvrFactory = class(TComObjectFactory) procedure UpdateRegistry(Register:Boolean);override; end; implementation TMyIClass procedure TMyIClass.Initialize; begin inherited; FInitVal := 100; end; destructor TMyIClass.Destroy; begin inherited; end; functi
44、on TMyIClass.SampleMethod(val: Smallint): SYSINT; begin Result := val + FInitVal; end; TMySvrFactory procedure TMySvrFactory.UpdateRegistry(Register: Boolean); begin inherited; if Register then begin CreateRegKey(MyApp+ClassName, GUID, GUIDToString(Class_MySvr); end else begin DeleteRegKey(MyApp+Cla
45、ssName); end; end; initialization TMySvrFactory.Create(ComServer, TMyIClass, Class_MySvr, MySvr, , ciMultiInstance, tmApartment); end. Class_MySvr 是自定义的 CLSID,TMyIClass 是接口实现类,TMySvrFactory 是类工厂类。 COM 对象的初始化对象的初始化 procedure Initialize 是接口的初始化过程,而不是常见的 Create 方法。当客户端创建接口后,将首先执行里面的代码,与 Create 的作用一样。一个
46、 COM 对象的生存周期内,难免需要初始化类成员或者设置变量的初值,所以经常需要重载这个过程。 相对应的,destructor Destroy 则和类的标准析构过程一样,作用也相同。 类工厂注册类工厂注册 在代码的最后部分,假如使用 TComObjectFactory 来注册,就和前面所讲的完全一样了。我在这里刻意用类TMySvrFactory 继承了一次,并且重载了 UpdateRegistry 方法,以便向注册表中写入额外的内容。这是种小技巧,希望大家根据本文的思路,摸清 COM/DCOM 对象的 Delphi 实现结构后,可以举一反三。毕竟随心所欲的控制 COM 对象,能提供的功能远不如此。