Delphi中高级DLL的编写和调用

Delphi中高级DLL的编写和调用
(苏涌)

根据Delphi提供的有关 DLL编写和调用的帮助信息,你可以很快完成一般的 DLL编写和调用的 应用程序。本文介绍的主题是如何编写和调用能够传递各种参数(包括对象实例)的 DLL。例如, 主叫程序传递给 DLL一个ADOConnection 对象示例作为参数, DLL中的函数和过程调用通过该对象 实例访问数据库。

需要明确一些基本概念。对于 DLL,需要在主程序中包含 exports子句,用于向外界提供调用 接口,子句中就是一系列函数或过程的名字。对于主叫方(调用 DLL的应用程序或其它的 DLL), 则需要在调用之前进行外部声明,即external保留字指示的声明。这些是编写 DLL和调用 DLL必须 具备的要素。

另外需要了解Object Pascal 中有关调用协议的内容。在Object Pascal 中,对于过程和函数 有以下五种调用协议:

指示字 参数传递顺序 参数清除者 参数是否使用寄存器
register 自左向右 被调例程 是
pascal 自左向右 被调例程 否
cdecl 自右向左 调用者 否
stdcall 自右向左 被调例程 否
safecall 自右向左 被调例程 否

这里的指示字就是在声明函数或过程时附加在例程标题之后的保留字,默认为register,即是 唯一使用 CPU寄存器的参数传递方式,也是传递速度最快的方式;

pascal: 调用协议仅用于向后兼容,即向旧的版本兼容;
cdecl: 多用于 C和 C++语言编写的例程,也用于需要由调用者清除参数的例程;
stdcall: 和safecall主要用于调用Windows API 函数;其中safecall还用于双重接口。
在本例中,将使用调用协议cdecl ,因为被调用的 DLL中,使用的数据库连接是由主叫方传递 得到的,并且需要由主叫方处理连接的关闭和销毁。

下面是 DLL完整源程序和主叫程序完整源程序。包括以下四个文件:

    Project1.DPR {主叫程序}
Unit1.PAS {主叫程序单元}
Project2.DPR {DLL}
Unit2.PAS {DLL单元}
{---------- DLL 主程序 Project2.DPR ----------}
library Project2;
uses
SysUtils,
Classes,
Unit2 in 'Unit2.pas' {Form1};
{$R *.RES}
{ 下面的语句用于向调用该 DLL的程序提供调用接口 }
exports
DoTest;       { 过程来自单元Unit2 }
begin
end.
{---------- DLL中的单元 Unit2.PAS ----------}
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, ADODB, StdCtrls, Menus;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;{ 本地数据库连接 }
Memo1: TMemo;                  { 用于显示信息   }
private
public
end;
{ 该过程向外提供 }
procedure DoTest(H: THandle;           { 获得调用者的句柄       }
AConn: TADOConnection;{ 获得调用者的数据库连接 }
S: string;            { 获得一些文本信息       }
N: Integer);          { 获得一些数值信息       }
cdecl;                { 指定调用协议           }
implementation
{$R *.DFM}
procedure DoTest(H: THandle; AConn: TADOConnection; S: string; N: Integer);
begin
Application.Handle := H;              { 将过程的句柄赋值为调用者的句柄 }
{ 上面语句的作用在于, DLL的句柄和调用者的句柄相同,在任务栏中就不会   }
{ 各自出现一个任务标题了。                                             }
with TForm1.Create(Application) do try{ 创建窗体                       }
Memo1.Lines.Append('成功调用');     { 显示一行信息                   }
ADOConnection1 := AConn;            { 获得数据库连接的实例           }
Memo1.Lines.Append(
ADOConnection1.ConnectionString +
' - ' + S + ' - ' + IntToStr(N)); { 根据得到的参数显示另一行信息   }
ShowModal;                          { 模式化显示窗体                 }
finally
Free;                               { 调用结束时销毁窗口             }
end;
end;
end.
{---------- 调用者 Project1.DPR,很普通的工程文件 ----------}
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
{---------- 调用者单元Unit1.PAS ----------}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Db, ADODB;
type
TForm1 = class(TForm)
Button1: TButton;   { 按此按钮进行调用 }
ADOConnection1: TADOConnection;         { 本地数据库连接,将传递给 DLL }
procedure Button1Click(Sender: TObject);{ 调用 DLL}
private
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{ 外部声明必须和 DLL中的参数列表一致,否则会运行时错误    }
procedure DoTest(H: THandle;             { 传递句柄       }
AConn: TADOConnection;  { 传递数据库连接 }
S: string;              { 传递文本信息   }
N: Integer);            { 传递数值信息   }
cdecl;                  { 指定调用协议   }
external 'Project2.dll';{ 指定过程来源   }
{ 调用过程 }
procedure TForm1.Button1Click(Sender: TObject);
begin
DoTest(Application.Handle,
ADOConnection1,
'Call OK',
256);
end;
end.

上面的可以传递一个adoconnection连接

看下面的传递一个chart就可以,但传递一个adotable就不行了

dll中如下
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, TeeProcs, TeEngine, Chart, StdCtrls, Buttons, DB,
  Grids, DBGrids, ADODB;

type
  Tfun = ^Tchart;
  TfunAdotable = ^Tadotable;
  TForm1 = class(TForm)
    Chart1: TChart;
    BitBtn1: TBitBtn;
    ADOConnection1: TADOConnection;
    ADOTable1: TADOTable;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
procedure performdll(ahandle: thandle; afun: tfun; funAdotable: TfunAdotable); stdcall; external 'dll.dll' name 'performdll';

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
var myfun: Tfun;
  funAdotable: TfunAdotable;
begin
  myfun := @chart1;
  performdll(handle, myfun, funAdotable);
end;

end.


exe调用程序如下:
unit dllmain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, TeeProcs, TeEngine, Chart, DB, ADODB,
  DBCtrls;

type
  Tfun = ^Tchart;
  TfunAdotable = ^tadotable;

  TForm1 = class(TForm)
    Button1: TButton;
    DBNavigator1: TDBNavigator;
    DataSource1: TDataSource;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
function performdll(ahandle: thandle; afun: tfun; funAdotable: TfunAdotable): integer; stdcall;

var
  Form1: TForm1;
  fun: tfun;
  myfunAdotable: TfunAdotable;


implementation

{$R *.dfm}

function performdll(ahandle: thandle; afun: tfun; funAdotable: TfunAdotable): integer; stdcall;
begin
  application.Handle := ahandle;
  form1 := tform1.Create(application);
  try
    form1.Caption := '导入数据...';
    fun := afun;
    showmessage('1');
    myfunAdotable := funAdotable;
    showmessage('2');
    //form1.DataSource1.DataSet:=myfunAdotable^;
    showmessage('3');
    form1.Show;
    result := 1
  finally
    //mainfrm.CLOSE;
    //mainfrm.free;
  end;



end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  fun^.Color := clred;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  showmessage('d');
  myfunAdotable^.close;    //执行到此出错?????????????
  showmessage('d');
  myfunAdotable^.Open;
  if not myfunAdotable^.Eof then
  begin
    showmessage('2');
    myfunAdotable^.Next;
  end;
end;

end.


高手请解答?????!!!!!!!!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值