Delphi 中的DLL 封装和调用对象技术

  

  

Delphi用DLL来封装对象的技术主要有三种:

用接口实现

用纯虚和抽象类方法实现

用类引用实现

前两种,都是在DLL中生成类实例;第3种通过在调用方生成实例。三种方法的共同局限如下:

调用方只能调用封装类中的virtual方法;

调用方和提供方都必须提供类的描述,接口实现中需要提供接口描述(COM方法例外);

不能创建DLL包含对象的派生类(接口派生除外)。

首先,用接口实现当然包括COM实现,不过由于COM是一种实现接口技术的独立门类,所以在下面说的接口实现中不包括这方面的东西。其次用纯虚和抽象类方法实现,在《Delphi 6 Developer‘s Guide》中提及的inc文件作为公用的头文件,和刘艺在《Delphi面向对象编程思想》中提及的方法本质上是一样的。无非都是为了在调用方加入abstract关键字,而无需方法实现,从而使得编译通过。inc文件的方法是利用宏指令来达到统一处理,不用inc方法是在两处都需要进行描述。

下面用一个例子来展示所以上面提到的集中方法。

调用方主要文件列表为:

UnitMain.pas 调用DLL的界面

UnitPublic.pas 第二种方法在调用端的类描述文件

UnitIDest.pas 接口方法和类引用方法的类描述文件

IncDemo.inc 利用inc文件实现的类描述文件

DLL工程主要文件列表为:

ProDLLDemo.dpr DLL工程文件

UnitDLLDemo.pas 所有类实现部分的文件

UnitIDest.pas 接口方法和类引用方法的类描述文件

IncDemo.inc 利用inc文件实现的类描述文件

在方法的归纳上如有遗漏,有请指教。

UnitMain.pas 源代码:

unit UnitMain;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, UnitPublic, UnitIDest;

{$I IncDemo.inc}

// 用于Inc方法的宏指令,如果不是用该方法可去掉上面那行

type

TfmMain = class(TForm)

Memo1: TMemo;

btnUseAbstract: TButton;

btnUseReference: TButton;

btnUseInterface: TButton;

btnUseInc: TButton;

procedure btnUseAbstractClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure btnUseInterfaceClick(Sender: TObject);

procedure btnUseReferenceClick(Sender: TObject);

procedure btnUseIncClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

fmMain: TfmMain;

function GetNewspaper: TNewspaper; external 'ProDLLDemo.dll';

function GetCircle: ICircle; external 'ProDLLDemo.dll';

function GetBall: TBallClass; external 'ProDLLDemo.dll';

function GetCar: TCar; external 'ProDLLDemo.dll';

implementation

{$R *.dfm}

procedure TfmMain.FormCreate(Sender: TObject);

begin

memo1.Lines.Clear;

end;

// abstract, virtual 方法示例

procedure TfmMain.btnUseAbstractClick(Sender: TObject);

var

NewspaperObj: TNewspaper;

Info: pchar;

i: integer;

begin

NewspaperObj := GetNewspaper;

if NewspaperObj = nil then

memo1.Lines.Add('Create newspaper object failed!')

else

begin

try

GetMem(Info, 255);

i := NewspaperObj.Read(Info);

memo1.Lines.Add('Create newspaper object successed!');

memo1.Lines.Add('read : ' + Info + ' return code : ' + inttostr(i));

finally

FreeMem(Info);

NewspaperObj.Free;

end;

end;

end;

// interface方法示例

procedure TfmMain.btnUseInterfaceClick(Sender: TObject);

var

CircleObj: ICircle;

Info: pchar;

i: integer;

begin

CircleObj := GetCircle;

if CircleObj = nil then

memo1.Lines.Add('Create circle object failed!')

else

begin

try

GetMem(Info, 255);

i := CircleObj.Scroll(Info);

memo1.Lines.Add('Create circle object successed!');

memo1.Lines.Add('scroll : ' + Info + ' return code : ' + inttostr(i));

finally

FreeMem(Info);

CircleObj := nil;

end;

end;

end;

// class reference方法示例

procedure TfmMain.btnUseReferenceClick(Sender: TObject);

var

BallObj : TIBall;

Info: pchar;

i: integer;

begin

BallObj := GetBall.Create;

if BallObj = nil then

memo1.Lines.Add('Create ball object failed!')

else

begin

try

GetMem(Info, 255);

i := BallObj.Play(Info);

memo1.Lines.Add('Create ball object successed!');

memo1.Lines.Add('play : ' + Info + ' return code : ' + inttostr(i));

finally

FreeMem(Info);

BallObj.Free;

end;

end;

end;

// .inc文件方法示例

procedure TfmMain.btnUseIncClick(Sender: TObject);

var

CarObj : TCar;

Info: pchar;

i: integer;

begin

CarObj := GetCar.Create;

if CarObj = nil then

memo1.Lines.Add('Create car object failed!')

else

begin

try

GetMem(Info, 255);

i := CarObj.Run(Info);

memo1.Lines.Add('Create car object successed!');

memo1.Lines.Add('car : ' + Info + ' return code : ' + inttostr(i));

finally

FreeMem(Info);

CarObj.Free;

end;

end;

end;

end.

UnitPublic.pas源代码:

unit UnitPublic;

interface

type

// ----- virtual, abstract的类定义 -----

TPaper = class(TObject);

TNewspaper = class(TPaper)

public

function Read(info : pchar) : integer; virtual; abstract;

end;

implementation

end.

UnitIDest.pas源代码:

unit UnitIDest;

interface

type

ICircle = interface

['{A971701F-96EC-4201-9266-57F982805B6E}']

function Scroll(Info : pchar) : integer;

end;

TIBall = class(TObject)

public

constructor Create; virtual; abstract;

destructor Destroy; virtual; abstract;

function Play(info : pchar) : integer; virtual; abstract;

end;

TBallClass = class of TIBall;

implementation

end.

IncDemo.inc源文件:

type

TCar = class(TObject)

public

function Run(info: pchar): integer; virtual; {$IFNDEF INCTEST} abstract; {$ENDIF}

end;

ProDLLDemo.dpr源文件:

library ProDLLDemo;

uses

SysUtils, Classes,

UnitDLLDemo in 'UnitDLLDemo.pas',

UnitIDest in 'UnitIDest.pas';

{$R *.res}

function GetNewspaper : TNewspaper;

begin

result := TNewspaper.Create;

end;

function GetCircle : ICircle;

begin

result := TCircle.Create;

end;

function GetBall : TBallClass;

begin

result := TBall;

end;

function GetCar : TCar;

begin

result := TCar.Create;

end;

exports

GetNewspaper,

GetCircle,

GetBall,

GetCar;

end.

UnitDLLDemo.pas源代码:

unit UnitDLLDemo;

{$DEFINE INCTEST}

interface

uses Sysutils, UnitIDest;

{$I IncDemo.inc}

{ ----- 利用纯虚和抽象类实现 ----- }

type

TPaper = class(TObject)

end;

TNewspaper = class(TPaper)

public

constructor Create;

destructor Destroy;

function Read(info: pchar): integer; virtual;

end;

{ ----- 利用接口实现 ----- }

type

TShape = class(TInterfacedObject)

end;

TCircle = class(TShape, ICircle)

public

constructor Create;

destructor Destroy;

function Scroll(info: pchar): integer;

end;

{ ----- 利用类引用实现 ----- }

type

TBall = class(TIBall)

public

constructor Create;override;

destructor Destroy;override;

function Play(info : pchar) : integer; override;

end;

implementation

{ TNewspaper }

constructor TNewspaper.Create;

begin

inherited Create;

end;

destructor TNewspaper.Destroy;

begin

inherited;

end;

function TNewspaper.Read(info: pchar): integer;

var

str: string;

begin

if info <> nil then

begin

str := self.ClassName;

strCopy(info, PChar(str));

end;

result := 1;

end;

{ TCircle }

constructor TCircle.Create;

begin

inherited Create;

end;

destructor TCircle.Destroy;

begin

inherited;

end;

function TCircle.Scroll(info: pchar): integer;

var

str: string;

begin

if info <> nil then

begin

str := self.ClassName;

strCopy(info, PChar(str));

end;

result := 2;

end;

{ TBall }

constructor TBall.Create;

begin

// inherited Create;

end;

destructor TBall.Destroy;

begin

// inherited;

end;

function TBall.Play(info: pchar): integer;

var

str: string;

begin

if info <> nil then

begin

str := self.ClassName;

strCopy(info, PChar(str));

end;

result := 3;

end;

{ ----- 利用Inc文件实现 ----- }

function TCar.Run(info: pchar): integer;

var

str: string;

begin

if info <> nil then

begin

str := self.ClassName;

strCopy(info, PChar(str));

end;

result := 4;

end;

end.

[参考文献]:

1. Delphi面向对象编程思想,第8章,刘艺, 2003.9, 机械工业出版社.

2. Delphi 6 Developer‘s Guide, p209, Steve Teixeira, SAMS, 2001.