奇趣技术网 收藏本站
设为主页
商务合作
首页 新闻中心 行业动态 软件新闻 安全资讯 病毒预警 漏洞发布 操作系统 Dos Win9x Win2000 WinXP Win2003 WinVista Linux Unix
数据库 DB2 Access MSSQL MySQL Oracle Sybase 编程技术 ASP PHP JSP CGI/Perl XML .Net C/C++/C# VB VC Delphi Java 汇编
安全技术 安全教学 工具介绍 漏洞利用 病毒防范 入侵检测 防火墙 安全防范 汉化破解 攻击实例 加密解密 技术论坛
中华网络安全联盟 >> 程序开发 >> Delphi >> 基于Delphi的接口编程入门
程序开发
Asp
PHP
JSP
CGI/Perl
XML
.Net
C/C++/C#
Visual Basic
Visual C++
Delphi
Java
汇编语言
  • Delphi实现网页表单数

  • 用Delphi开发Web服务数

  • Delphi中利用钩子实现

  • 一个判断定文件是否为

  • 把Flash文件转换为Exe

  • 用Delphi实现文件下载

  • Delphi中保存图像列表

  • 在Delphi中使用Create

  • 基于Delphi的接口编程入门
    字体:

    中华网络安全联盟    作者:佚名    来源:网络转载    时间:2006-3-22

      为什么使用接口?

      举个例子好了:有这样一个卖票服务,电影院可以卖票,歌剧院可以卖票,客运站也可以卖票,那么我们是否需要把电影院、、歌剧院和客运站都设计成一个类架构以提供卖票服务?要知道,连经理人都可以卖票,很显然不适合把经理人也包括到卖票服务的继承架构中,我们需要的只是一个共通的卖票服务。于是,卖票的服务是个接口,电影院、歌剧院什么的只要都遵循这样一个服务定义就能很好地相互交互和沟通(如果须要的话)。

      如何在Delphi中使用接口

      1、声明接口

    IMyInterface = interface(IInterface) //说明(1)
    ['{63E072DF-B81E-4734-B3CB-3C23C7FDA8EA}'] //说明(2)
    function GetName(const str: String): String; stdcall;

    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; //说明(3)
    function _AddRef: Integer; stdcall; //使接口引用数加1。
    function _Release: Integer; stdcall;//使接口引用数减1,当小于等于0时作释放动作。
    end;

      说明(1):如果有继续关系则在括号里填父接口,否则省却,如:IMyInterface = interface这样就行。

      说明(2):此GUID可选,如果要实现具有COM特性的接口的话则需要加上,Delphi中对于有GUID的接口在运行时在VMT表的预定位置生成接口的信息,如接口方法的定义、方法参数定义能详细信息。

      说明(3):接口必须实现这三个函数。

      2、接口的实现

      接口服务是由类来实现的。

    TIntfClass = class(TObject, IMyInterface)
    private
     FCounter: Integer;
     FRefCount: Integer;
    public
     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
     ...
    end;

      3、获取接口

      a. 使用类型转换。 如:

    var aIntf: IMyInterface;
    begin
     aObj := TIntfClass.Create;
    try
     aIntf := (IMyInterface(aObj);
     ...

      b. 利用Delphi编译器内建机制。 如:aIntf := aObj。

      c. 利用对象的QueryInterface方法。如OleCheck(aObj.QueryInterface(IID, aIntf)); 只能存取有GUID的COM接口。

      d. 利用as操作符。

      使用as操作符必须符合下面条件:

      1.接口必须明确地指定是从IInterface接口继承下来。

      2.必须拥有GUID值

      在Delphi7中接口的实现类还必须是从TInterfacedObject继承下来才行,如:

    TIntfClass = class(TInterfacedObject, IMyInterface)

      4、接口和对象生命期

      因为Delphi会自行检查接口如果在使用后没有释放而在生成的程序里加上释放代码,但也因这样带来了问题,如下面代码:

    var
     i: Integer;
     aObj: TIntfClass;
     aIntf: IMyInterface;
    begin
     aObj := TIntfclass.Create;
     try
      aIntf := aObj;
      aIntf.GetName...
     finally
      aIntf := nil;
      FreeAndNil(aObj);
    end;

      上面的代码执行的话会产生存取违规错误,是因为对接口置nil时已释放接口,而FreeAndNil(aObj)会再释放aIntf一次,而在对aIntf置
    nil时已释放了该对象。解决这个问题只要不让接口干扰对象的生命期就可以了,在Release中只需减引用计数而不做释放的动作。

    function TIntfClass._Release: Integer;
    begin
    Result := InterlockedDecrement(FRefCount);
    end;

      5、接口的委托(Interface Delegation)

      分为两种:

      1. 对象接口委托

      2. 类对象委托。

      . 对象接口委托,假如已有下面接口定义:

    IImplInterface = interface(IInterface)
    function ConvertToUSD(const iNTD: Integer): Double;
    function ConvertToRMB(const iNTD: Integer): Double;
    end;

      接着有一个类实现了该接口:

    TImplClass = class(TObject, IImplInterface)
    private
     FRefCount: Integer;
    public
     function ConvertToUSD(const iNTD: Integer): Double;
     ...
    end;

    implementation

    function TImplClass.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
    if GetInterface(IID, Obj) then
     Result := 0
    else
     Result := E_NOINTERFACE;
    end;

    function TImplClass._Release: Integer;
    begin
     Result := InterlockedDecrement(FRefCount);
    if Result = 0 then
     Destroy;
    end;
    ... ...

      现在有另外一个类TIntfServiceClass要实现IImplInterface接口,不用重新定义,只须使用上面的TImplClass就可以:

    TIntfServiceClass = class(TObject, IImplInterface)
    private
     FImplService: IImplInterface;
     //FSrvObj: TImplClass; //如果是用类对象委托的话
    public
     Constructor Create; overload;
     Destructor Destroy; override;
     Constructor Create(aClass: TClass); overload;
     property MyService: IImplInterface read FImplService implements IImplInterface;
     // property MyService: TImplClass read FSrvObj implements IImplInterface; //如果是用对象委托的话。
    end;

      实现如下:

    constructor TIntfServiceClass.Create;
    begin
     FImplService := TImplClass.Create;
    end;

    constructor TIntfServiceclass.Create(aClass: TClass);
    var
     instance: TImplClass;
    begin
     instance := TImplClass(aClass.NewInstance);
     FImplService := instance.Create;
    end;

    destructor TIntfServiceClass.Destroy;
    begin
     FImplService := nil; //遵照TImplClass使用引用计数来控制对象生命周期,看TImplClass的Destroy实现。
     inherited;
    end;

      6、接口和RTTI

      Delphi中在VMT-72位移处定义了接口哥格指针:vmtIntfTable = -72。

      相关函数:

    GetInterfaceCount; //获取接口数量。
    GetInterfaceTable; //获取接口表格。

      相关结构:

    TInterfaceEntry = packed record
    IID: TGUID;
    VTable: Pointer;
    IOffset: Integer;
    ImplGetter: Integer;
    end;

    PInterfaceTable = ^TInterfaceTable;
    TInterfaceTable = packed record
    EntryCount: Integer;
    Entries: array[0..9999] of TInterfaceEntry;
    end;

      Self是指向VMT指针的指针,所以:Self.GetInterfaceTable.EntryCount等价于:

    aPtr := PPointer(Integeer((Pointer(Self))^) + vmtIntfTable)^;

      只要在声明中使用M+/M-指令就能在Delphi中编译出的程序里添加RTTI信息,如:

    {$M+}
    iInvokable = interface(IInterface)
    {$M-}

      接口的RTTI信息由TIntfMetaData记录结构定义:

    TIntfMetaData = record
    name: String; //接口名称
    UnitName: String; //接口声明的程序单元名称
    MDA: TIntfMethEntryArray; //储存接口中方法信息的动态数组
    IID: TGUID; //接口的GUID值
    Info: PTypeInfo; //描述接口信息的指针
    AncInfo: PTypeInfo; //描述父代信息的指针
    NumAnc: Integer; //此接口继承自父代接口的方法数目
    end;

      TIntfMethEntryArray的定义如下:

    type
     TCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall, ccSafeCall);
     TIntfMethEntry = record
     Name: String; //方法名称
     CC: TCallConv; //调用惯例
     Pos: Integer; //方法在接口中的位置
     ParamCount: Integer; //方法的参数数目
     ResultInfo: PTypeInfo; //描述方法回传类型的信息指针
     SelfInfo: PTypeInfo; //描述方法本身的信息指针
     Params: TIntfParamEntryArray; //描述参数信息的动态数组
     HasRTTI: Boolean; //这个方法是否拥有RTTI信息的布尔值
    end;

    TIntfMethEntryArray = array of TIntfMethEntry;

      参数信息TIntfParamEntry定义:

    TIntfParamEntry = record
    Flags: TParamFlags;
    Name: String;
    Info: PTypeInfo;
    end;

    TTypeInfo = record
    Kind: TTypeKind; //数据类型
    Name: ShortString; //类型信息的字符串格式
    end;

    字体:
     
    设为主页 收藏本站 联系我们 友情连接 商务合作 网友留言
    Copyright©2006-2008 中华网络安全联盟 All rights reserved.