Delphi用DLL來(lái)封裝對(duì)象的技術(shù)主要有三種:
用接口實(shí)現(xiàn)
用純虛和抽象類(lèi)方法實(shí)現(xiàn)
用類(lèi)引用實(shí)現(xiàn)
前兩種,都是在DLL中生成類(lèi)實(shí)例;第3種通過(guò)在調(diào)用方生成實(shí)例。三種方法的共同局限如下:
調(diào)用方只能調(diào)用封裝類(lèi)中的virtual方法;
調(diào)用方和提供方都必須提供類(lèi)的描述,接口實(shí)現(xiàn)中需要提供接口描述(COM方法例外);
不能創(chuàng)建DLL包含對(duì)象的派生類(lèi)(接口派生除外)。
首先,用接口實(shí)現(xiàn)當(dāng)然包括COM實(shí)現(xiàn),不過(guò)由于COM是一種實(shí)現(xiàn)接口技術(shù)的獨(dú)立門(mén)類(lèi),所以在下面說(shuō)的接口實(shí)現(xiàn)中不包括這方面的東西。其次用純虛和抽象類(lèi)方法實(shí)現(xiàn),在《Delphi 6 Developer‘s Guide》中提及的inc文件作為公用的頭文件,和劉藝在《Delphi面向?qū)ο缶幊趟枷搿分刑峒暗姆椒ū举|(zhì)上是一樣的。無(wú)非都是為了在調(diào)用方加入abstract關(guān)鍵字,而無(wú)需方法實(shí)現(xiàn),從而使得編譯通過(guò)。inc文件的方法是利用宏指令來(lái)達(dá)到統(tǒng)一處理,不用inc方法是在兩處都需要進(jìn)行描述。
下面用一個(gè)例子來(lái)展示所以上面提到的集中方法。
調(diào)用方主要文件列表為:
UnitMain.pas 調(diào)用DLL的界面
UnitPublic.pas 第二種方法在調(diào)用端的類(lèi)描述文件
UnitIDest.pas 接口方法和類(lèi)引用方法的類(lèi)描述文件
IncDemo.inc 利用inc文件實(shí)現(xiàn)的類(lèi)描述文件
DLL工程主要文件列表為:
ProDLLDemo.dpr DLL工程文件
UnitDLLDemo.pas 所有類(lèi)實(shí)現(xiàn)部分的文件
UnitIDest.pas 接口方法和類(lèi)引用方法的類(lèi)描述文件
IncDemo.inc 利用inc文件實(shí)現(xiàn)的類(lèi)描述文件
在方法的歸納上如有遺漏,有請(qǐng)指教。
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);