作者:巴哈姆特  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之间划上等号!

Delphi COM对象的更多相关文章

  1. 多线程的基本概念和Delphi线程对象Tthread介绍

    多线程的基本概念和Delphi线程对象Tthread介绍 作者:xiaoru    WIN 98/NT/2000/XP是个多任务操作系统,也就是:一个进程可以划分为多个线程,每个线程轮流占用CPU运行 ...

  2. delphi:临界区对象TCriticalSection(Delphi) 与 TRtlCriticalSection 的区别

    临界区对象TCriticalSection(Delphi) 与 TRtlCriticalSection 的区别 TRtlCriticalSection 是一个结构体,在windows单元中定义: 是I ...

  3. 重置delphi Printer对象

    http://www.efg2.com/Lab/Library/UseNet/1999/0714b.txt From: "Nick Ryan" <nick@avatardes ...

  4. Delphi 绘图对象

    来自:http://blog.csdn.net/lailai186/article/details/8755430 ========================================== ...

  5. Delphi栈对象

    来自:http://blog.csdn.net/iseekcode/article/details/5158985 ------------------------------------------ ...

  6. Delphi GDI对象之绘制位图

    http://www.cnblogs.com/pchmonster/archive/2012/07/06/2579334.html 绘制位图(Drawing Bitmaps) 绘制位图听起来似乎很难, ...

  7. Delphi中流对象的应用

    Delphi的流对象(TStream的派生对象)有如下读写函数: function Read(var Buffer; Count: Longint): Longint;function Write(c ...

  8. Delphi的对象注销方法Destroy和free

    当您使用完对象后,您应该及时撤销它,以便把这个对象占用的内存释放出来.您可以通过调用一个注销方法来撤销您的对象,它会释放分配给这个对象的内存. Delphi的注销方法有两个:Destroy和Free. ...

  9. Delphi - 互斥对象下实现系统的单例模式

    使用CreateMutex函数创建互斥对象 利用Windows系统函数CreateMutex(),找出当前系统是否已经存在指定进程的实例,如果没有则创建一个互斥体. CreateMutex函数原型如下 ...

随机推荐

  1. pycharm windows 远程修改服务器代码

    配置过程 本机环境 操作系统:win10 IDE:Pycharm 远程服务器 操作系统:ubuntu 4.4.0 配置了ssh,可以使用ssh进行远程登陆 配置Deployment 首先,在pycha ...

  2. Delphi 字符串函数SysUtils单元 AnsiSameStr、AnsiSameText、AnsiCompareStr、AnsiCompareText、AnsiCompareFileName、AnsiUpperCase、AnsiLowerCase、AnsiUpperCaseFileName、AnsiLowerCaseFileName、AnsiPos、AnsiQuotedStr

    USES 单元 SysUtils 非 StrUtils AnsiSameStr.AnsiSameText.AnsiCompareStr.AnsiCompareText.AnsiCompareFileN ...

  3. html2canvas截图白边显示问题

    html2canvas(document.getElementById('resource_chart'),{ useCORS:true, logging:false, width:$('#resou ...

  4. Network基础(一):配置计算机名及工作组、TCP/IP地址配置、网络连通性测试

    一.配置计算机名及工作组 目标: 本例要求为修改计算机名并加入工作组: 设置计算机名:姓名拼音 设置工作组名:TARENA-NETWORK 方案: 修改Windows 2008服务器的计算机名(可设为 ...

  5. [CSP-S模拟测试53]题解

    A.u 只涉及到区间修改可以考虑差分,然而如果每一行都差分复杂度还是过高.我们发现差分标记也是连续的(一行横着的一行斜着的),所以可以维护两个 差分的差分,扫两遍统计即可. #include<c ...

  6. PHP基础知识总结(三) 流程控制、函数、类对象和数据库

    PHP基础语法 1.流程控制 条件语句:if  elseif  else / switch if($a == 1){ …… } elseif ($a == 2){ …… } else{ …… } 循环 ...

  7. pandas中的quantile函数

    https://blog.csdn.net/weixin_38617311/article/details/87893168 data.price.quantile([0.25,0.5,0.75]) ...

  8. js匿名函数测试

    js匿名函数测试 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  9. Struts1.3——使用MyEclipse集成工具开发Struts

    前面两篇通过手工写代码,手工配置struts-config.xml文件的方法来开发了一个最简单的struts项目,通过手工的方式旨在学习底层原理细节.当熟悉了以后,我们就不需要再通过纯手工的方式来开发 ...

  10. 使用yarn搭建vue项目

    今天尝试了一下用yarn的方式搭建vue项目,方法其实是和npm的用法一样.但是在创建过程中报错了.现在整理一下,便于后期查错时使用. 以windows系统为例 1.全局安装yarn,三种方式 官网上 ...