转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> Delphi程序 >> 正文
Delphi下的COM编程         ★★★★

Delphi下的COM编程

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2117 更新时间:2009/4/23 18:25:45
持IClassFactory接口的对象;例程DllCanUnloadNow判断DLL是否可从内存卸载;DllRegisterServer

和DllUnregisterServer负责DLL的注册和解除注册,其具体的功能由ComServer实现。

接口类的具体实现

好了,现在自动生成代码的来龙去脉已经解释清楚了,下一步就是由我们来添加接口方法的实现代码。在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 ValInt 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找不接口的话,将报告“无法向注册表写入项”。如果接口定义不一致,则会报告“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.Button1Click(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;

最终值是从当前程序外的一个“接口”返回的,我们甚至可以不知道这个接口的实现!第一次接触COM的人,成功执行此程序并弹出对话框后,

也许会体会到一种技术如斯奇妙的感觉,因为你仅仅调用了“接口”,就可以完成你猜测中的东西。

创建一个分布式DCOM(自动化接口)

IDispatch

在delphi6之前的版本中,所有接口的祖先都是IUnknown,后来为了避免跨平台操作中接口概念的模糊,又引入了IInterface接口。

使用向导生成DCOM的步骤和COM几乎一致。而生成的代码仅将接口类的父类换为TAutoObject,类工厂类换为TAutoObjectFactory。这其实没有

太大的不同,因为TAutoObject等于是一个标准COM外加IDispatch接口,而TAutoObjectFactory是从TTypedComObjectFactory直接继承的:

TAutoObject = class(TTypedComObject, IDispatch)

TAutoObjectFactory = class(TTypedComObjectFactory)

自动化服务器支持双重接口,而且必须实现IDispatch。因讨论范畴限制,本文只能简单提出,IDispatch是DCOM和COM技术实现上的一个重要区

别。打开_TLB.pas单元,可以找到Ixxx = interface(IDispatch)和Ixxx = dispinterface的定义,这在前面COM的例子里面是没有的。

创建过程中的差异

使用类型库编辑器的时候,有两处和COM不同的地方。首先Return Type必须选择HRESULT,否则会提示错误,这是为了满足双重接口的需要。当

Return Type选择HRESULT后,你会发现方法定义将变成procedure(过程)而不是预想中的function(函数)。

怎么才能让方法有返回值呢?还需要在Parameters最后多添加一个参数,然后将该参数改名与方法名一致,设置参数类型为指针(如果找不到

某种类型的指针类型,可以直接在类型后面加*,如图,BSTR*是BSTR的指针类型)。最后在Modifier列设置Parameter Flags为RetVal,同时

Out将被自动选中,而In将被取消。

刷新后,得到下列代码。添加方法的具体实现,大功告成:

  TSampleAuto = class(TAutoObject, ISampleAuto)

  protected

    function GetAutoSerInfo(ValInt: SYSINT;const ValStr: WideString): WideString; safecall;

  end;

远程接口调用

远程接口的调用需要使用CreateRemoteComObject函数,其它如接口的声明等等与COM接口调用相同。CreateRemoteComObject函数比

CreateComObject 多了一个参数,即服务器的计算机名称,这样就比COM多出了远程调用的查询能力。前面“接口定义说明”一节的代码可以对

照CreateComObject、CreateRemoteComObject的区别。

自定义COM的对象

接口一个重要的好处是:发布一个接口,可以不断更新其功能而不用升级客户端。因为不论应用升级还是业务改变,客户端的调用方式都是一

致的。

既然我们已经弄清楚Delphi是怎样实现一个接口的,那能否不使用向导,自己定义接口呢?这样做可以用一个接口继承出不同的接口实现类,

来完成不同的功能。同时也方便了小组开发、客户端开发、进程内/外同步编译以及调试。

接口单元:xxx_TLB.pas

前面略讲了接口的定义需要注意的方面。接口除了没有实例化外,它与普通类还有以下区别:接口中不能定义字段,所有属性的读写必须由方

法实现;接口没有构造和析构函数,所有成员都是public;接口内的方法不能定义为virtual,dynamic,abstract,override。

首先我们要建立一个接口。前面讲过接口的定义只存在于一个地方,即xxx_TLB.pas单元里面。使用类型库编辑器可以产生这样一个单元。还是

在新建项目的ActiveX页,选择最后一个图标(Type Library)打开类型库编辑器,按F12键就可以看到TLB文件(保存为.tlb)了。没有定义任

何接口的时候,TLB文件里除了一大段注释外只定义了LIBID(类型库的GUID)。假如关闭了类型库编辑器也没有关系,可以随时通过菜单View

– Type Library打开它。

先建立一个新接口(使用向导的话这步已经自动完成了),然后如前面操作一样建立方法、属性…生成的TLB文件内容与向导生成_TLB单元大致

相同,但仅有定义,缺乏“co+类名”之类的接口创建代码。

再观察代码,将发现接口是从IDispatch继承的,必须将这里的IDispatch改为IUnknown。保存将会得到.tlb文件,而我们想要的是一个单元

(.pas)文件,仅仅为了声明接口,所以把代码拷贝复制并保存到一个新的Unit。

自定义CLSID

从注册和调用部分可以看出CLSID的重要作用。CLSID是一个GUID(全局唯一接口表示符),用来标识对象。GUID是一个16个字节长的128位二进

制数据。Delphi声明一个GUID常量的语法是:

  Class_XXXXX : TGUID = ''''{xxxxxxxx-xxxxx-xxxxx-xxxxx-xxxxxxxx}'''';

在Delphi的编辑界面按Ctrl+Shift+G键可以自动生成等号后的数据串。GUID的声明并不一定在_TLB单元里面,任何地方都可以声明并引用它。

接口类声明与实现

新建一个ActiveX Library工程,加入刚才定义的TLB单元,再新建一个Unit。我的TLB单元取名为MyDef_TLB.pas,定义了一个接口

IMyInterface = interface(IUnknown),以及一个方法function SampleMethod(val: Smallint): SYSINT; safecall;现在让我们看看全部接口

类声明及实现的代码:

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  SampleMethod(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;

function 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\''''+ClassName);

  end;

end;

initialization

  TMySvrFactory.Create(ComServer, TMyIClass, Class_MySvr,

      ''''MySvr'''', '''''''', ciMultiInstance, tmApartment);

end.

Class_MySvr是自定义的CLSID,TMyIClass是接口实现类,TMySvrFactory是类工厂类。

COM对象的初始化

procedure Initialize是接口的初始化过程,而不是常见的Create方法。当客户端创建接口后,将首先执行里面的代码,与Create的作用一样

。一个COM对象的生存周期内,难免需要初始化类成员或者设置变量的初值,所以经常需要重载这个过程。

相对应的,destructor Destroy则和类的标准析构过程一样,作用也相同。

类工厂注册

在代码的最后部分,假如使用TComObjectFactory来注册,就和前面所讲的完全一样了。我在这里刻意用类TMySvrFactory继承了一次,并且重

载了UpdateRegistry 方法,以便向注册表中写入额外的内容。这是种小技巧,希望大家根据本文的思路,摸清COM/DCOM对象的Delphi实现结构

后,可以举一反三。毕竟随心所欲的控制COM对象,能提供的功能远不如此。

(本文所有代码在Delphi6、Delphi7下编译执行通过)

全文完。

发表于 2005年05月27日 4:26 PM


上一页  [1] [2] 


[聊天工具]Google Suggest十大妙用  [聊天工具]保驾护航Web迅雷 全新版本给你更多安全
[聊天工具]玩转火狐的Cookie 让火狐狸吃好小甜饼!  [聊天工具]P2P下载的好工具 POCO完全攻略
[聊天工具]横扫一切高价话费 Vbuzzer八分钱国际长途任你打  [聊天工具]众人拾柴火焰高 改进迅雷于不经意间 迅雷
[聊天工具]中英文互翻 Google Toolbar4中文版试用手记  [聊天工具]巧用µTorrent 体验国外下载站的乐趣
[聊天工具]可远程搜索桌面—Google Desktop 3全新体验  [聊天工具]腾讯浏览器 TT 之实用技巧荟萃 TT,技巧荟萃
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台