Delphi面向对象学习随笔七:COM

作者:巴哈姆特
http://www.cnpack.org
(转载请注明出处并保持完整)

上一篇,我们介绍了接口。如果没有接触过COM对象的话,你会觉得接口真的很麻烦,也许会有:“还不如直接定义一个类更方便”的想法。
    的确,没有经过COM封装的接口确实比较麻烦。在我看来,没有经过COM封装的接口似乎没有存在的意义。那么,什么是COM对象呢?它有什么优点呢?接下来开始对COM对象进行一个简单的介绍:

COM是个二进制规范,它与实现的语言无关。这样,即使COM对象由不同的编程语言创建,运行在不同的进程空间和不同的操作系统平台,这些对象也能相互通信。COM既是规范,也是实现,它以COM库的形式提供了访问COM对象核心功能的标准接口以及一组API函数,这些API函数用于创建和管理COM对象。COM本质上仍然是客户服务器模式。客户(通常是应用程序)请求创建COM对象并通过COM对象的接口操纵COM对象。服务器根据客户的请求创建并管理COM对象。当然,客户和服务器这两种角色并不是绝对的。

记得我在刚刚接触COM对象的时候,我师傅曾经给我说过:“COM不是Dll,虽然它可能会以后缀名为dll文件呈现在你面前,但是它绝对不是我们传统意义上所说的dll(动态链接库)”。
    其实在我看来,进程内的COM对象应该是一个以dll为载体而提供一些特殊服务的特殊的动态链接库。当然,也有进程外的COM。

现在,我们演示怎么在Delphi中利用向导建立一个简单的COM模型。
    首先:打开Borland Delphi 7.1(不好意思,我一般都是用这个版本。什么?为什么是7.1?就是7.0加个Update1补丁包嘛-_-||)。
    然后:把Delphi默认为我们创建的Application关掉,并在菜单中选择File->New->Other,之后在弹出的窗口中找到ActiveX页,双击ActiveX Library图标。
    双击图标后,我们可以看到Delphi已经帮我们建立了一个ActiveX库,代码如下:

library Project1;

uses

  ComServ;

exports

  DllGetClassObject,    // 返回类工厂的接口

  DllCanUnloadNow,      // 是否可以释放该组件

  DllRegisterServer,    // 注册函数

  DllUnregisterServer;  // 反注册函数

{$R *.RES}

begin

end.

我们会看到,在工程中,Delphi已经帮我们定义好了四个输出函数(关于这几个函数更详细的说明,可以查阅更多的资料),我们先不管它们。
    接下来,我们再使用菜单File->New->Other并在ActiveX页中创建Com Object,这时,我们可以看到一个对话框:其中ClassName是我们的对象名、Instancing是对象创建模式、Threading Module为线程模式。我们使用NewComServer作为对象名,其他默认。OK后可以看到一个标题为“Project11.tlb”的窗口,这个我们可以在这个窗口中为接口添加新的方法,例如我们添加一个GetMessage方法。然后我们打开Unit1.pas可以看到如下代码:

unit Unit1;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses

  Windows, ActiveX, Classes, ComObj, Project1_TLB, StdVcl;

    // Project1_TLB 接口所在单元

type

  TNewComServer = class(TTypedComObject, INewComServer)

    // 实现接口的类

  protected

    function GetMessage: HResult; stdcall;

      // 我们刚刚添加的方法

    {Declare INewComServer methods here}

  end;

implementation

uses ComServ;

function TNewComServer.GetMessage: HResult;

begin

  MessageBox(0, \‘测试\‘, \‘提示\‘, $40);

  Result:= GetLastError; // 我添加的代码

end;

initialization

  TTypedComObjectFactory.Create(ComServer, TNewComServer, Class_NewComServer, ciMultiInstance, tmApartment);

    // 类工厂

end.

之后,我们编译这个工程(CTRL+F9)将会生成一个Project1.dll文件。保存并关闭这个工程。
    接着,我们编写一段代码来测试这个COM工程:创建一个普通的应用程序工程,并引用Project1_tlb单元:

var // 注意,在测试代码中也需要引用project1_tlb单元,由于我们的接口声明在该单元内

  NewComObject: INewComObject; // 声明接口

begin

  NewComObject:= CreateComObject(CLASS_NewComObject) as INewComObject; // 创建COM对象,

    //CLASS_NewComObject 的定义可以在Project1_tlb.pas里找到

  if NewComObject <> nil then

    begin

      NewComObject.GetMessageInfo; // 调用接口中的方法

      NewComObject:= nil; // 释放接口

    end

  else

    ShowMessage(\‘对象创建不成功\‘);

end;

注意我们在运行这个EXE之前,需要先把我们之前的COM工程注册给系统:开始->运行->regsvr32.exe \"...Project1.dll\"。看到注册成功的提示信息后,我们现在可以运行我们刚刚编写的那个测试程序来测试我们的COM对象了,看看执行测试代码后,是否弹出了一个标题为“提示”,内容为“测试”的对话框呢?

我们可以看到,在COM组件创建好以后,在EXE调用的时候是相当简单的,而且,当我们某个方法的实现细节发生改动,只要方法声明不变,那么在软件升级的时候,我们可以只升级我们需要升级的COM组件,而不需要改动其它的地方。这样可以有效的减轻维护的工作量。

当然,这个演示只是一个进程内的COM,至于更详细的说明,可以去参阅更多的资料。

友情提示:ActiveX是Windows下实现COM的一个组件规范。请不要把ActiveX和COM之间划上等号!

时间: 2024-08-04 23:54:15

Delphi面向对象学习随笔七:COM的相关文章

Delphi面向对象学习随笔九:后记

作者:巴哈姆特http://www.cnpack.org(转载时请注明出处并保持完整) 最后一篇了,呵呵!其实通过写这几篇笔记,也发现了我自己知识欠缺的部分.当然也通过各位高手的提点,让我把以前学习过的东西来了一次“体检”.    当然,错误也有,但是改了就还是好同志嘛,呵呵^_^ 随便介绍一下Delphi中的几个比较常用的类吧: TObject:    VCL中所有类的根类,即是说:VCL中所有的类/组件/控件都是从TObject中继承而来.TObject类中定义了基本的构造方法和析构方法.

Delphi面向对象学习随笔三:overload与override

作者:巴哈姆特(转载请注明出处并保持完整)    首先,我想单独说明一下overload,为什么呢?因为overload和对象化关联不大,所以,我感觉单独提出来说明比较好.    我们都知道,在Pascal语法规则中,同一个UNIT里是不能存在两个同名的函数的,例如: function func(): Boolean; function func(const x: Char): Boolean; 这样是会出语法错误的,原因是因为标识符规则限制.但是问题出来了,如果我们需要几个功能相似但是参数不同

Delphi面向对象学习随笔八:物理封装

作者:巴哈姆特http://www.cnpack.org(转载请注明出去并保持完整)前面说过的封装其实是逻辑意义上的封装.逻辑封装是对某一特定逻辑功能模块的封装,这个特定逻辑功能块可以是一个类,当然也可以是一个包,他们都有自己的逻辑边界.另一种封装方式,我们通常叫它为物理封装:物理封装其实是具体实现代码的物理集合,他可以以bpl,dll,com+等形式体现. 逻辑封装里,对象的传递.数据共享与调用相对要简单的多,只要我们引用类所定义的单元(unit)就可以直接访问类中public和publish

Delphi面向对象学习随笔二 编写第一个类

作者:巴哈姆特(转载请注明出处并保持完整) 这回,我们讨论怎么编写我们自己的第一个类.    在编写我们自己的类之前,首先要说的是“类的继承”.    记得前几天,我在和一个朋友讨论类的特点的时候,他说:“类是可以没有构造方法的!”其实类必须有至少一个构造方法的,但是他的话也不全错,可以理解成“我们可以不实现我们自己的构造方法”.    当我们没有显式的为类编写一个构造方法的时候,那么,看上去,这个类好象是没有构造方法,但是实际上,就算你没有为这个类编写一个属于你自己的构造方法的时候,该类还是有

Delphi面向对象学习随笔五:一个真正的类

作者:巴哈姆特(转载请注明出去并保持完整)写在前面的话:    本篇笔记完全属于我的个人主观观点,如有错误请指正^_^  类的定义:    首先,我想说的是,类并不是一些变量和函数简单的“拼凑”出来的.类应该是对于一个事物的抽象描述,而不是一个动作的抽象描述.怎么讲呢?    比如说:鞋子是一个事物,我们可以把它的特点抽象出来,并用计算机语言去描述成为一个类,而鞋子又分了凉鞋.皮鞋等,那么“凉鞋”和“皮鞋”则是“鞋子”的派生类.它们看上去是非常自然的.    那么,现在我有另外一个类,“初始化数

Delphi面向对象学习(-)

Delphi面向对象学习随笔一:类与对象的关系作者:巴哈姆特http://www.cnpack.org(转载请注明出处并保持完整)工作几年了,总想做点总结,于是有了这篇东西,叫随笔吧呵    本文只是写写我对对象化的理解,主观成分很多,或许有错误,希望大家指正^_^    PS: 本文的演示代码均以Delphi 的Object Pascal语法为准. 类与对象的关系    要讨论类与对象的关系,需要先说一下什么是类,什么是对象. 类:    类.我认为是一个集合,和数学中的集合一样,是一类事物的

linux学习随笔七

本次学习bash的特性 bash及其特性: shell:外壳 GUI   Gnome   KDE   Xfce shell的种类:CLI  sh csh  ksh bash  tcsh  zsh 进程:从每个进程看来,当前主机上只存在内核和当前进程.进程是程序的副本,进程是程序执行实例 bash特性: 1.命令历史.命令补全 2.管道.重定向 3.命令别名 4.命令行编辑 5.命令行展开 6.文件名通配 7.变量 8.编程 命令行编辑: 光标跳转:ctrl +A 行首, ctrl +E 行尾 c

lua面向对象学习随笔 --类与实例

面向对象最基本的就是两点:类,对象. 但是lua是无类型的,要实现面向对象只能模拟实现. 其实他们都是表,多了个__index属性,就模拟出了实现“类和继承”的效果. 面对Lua千万别用c++的类来类比,不然会误入歧途! 它就是一个table而已下面一个典型的定义一个“类”的方式. class={} function class:new(o) local o=o or {} setmetatable(o,self) self.__index=self o:ctor() return o end

面向对象学习随笔

面向对象中讲的属性与构造函数,现象与对象,继承多态,接口,抽象类都会用到类和对象.[所以类和对象的理解和运用很重要!] 类不能直接使用 对象才可以使用 class 类名                    {                                           }     类的里面应该定义什么:         a. 将这类事物拥有的共同特征定义为类的成员变量.         b. 将这类事物拥有的共同的功能定义为方法.(我们在自己写的类中 不要加static