Delphi中高级DLL的编写和调用

转载 2004年07月09日 02:07:00

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.


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

Delphi动态调用C++写的DLL

c++ DLL 文件,建议用最简单的c++编辑工具。不会加入很多无关的DLL文件。本人用codeblocks+mingw。不像 VS2010,DLL编译成功,调用的时候会提示缺其他DLL。 系统生成的...
  • mycoolme5
  • mycoolme5
  • 2016年04月13日 16:51
  • 533

Delphi程序调用C#.Net编译的DLL并打开窗体(详解)

转自: http://www.csframework.com/archive/2/arc-2-20110408-1307.htm Delphi程序调用C#.Net编译的DL...
  • hatchgavin
  • hatchgavin
  • 2014年12月16日 15:39
  • 5412

Delphi调用C# 编写dll动态库

Delphi调用C# 编写dll动态库
  • chenhongwu666
  • chenhongwu666
  • 2016年12月02日 15:48
  • 401

delphi编写与调用DLL

delphi编写DLL 下面在delphi中编写一个简单的dll,在该dll中只有一个max函数,返回2个数中的大数(Delphi 5.0) 1、New->DLL;取名为DLL_0001,编写代码...
  • ma123_ma123
  • ma123_ma123
  • 2016年07月13日 18:09
  • 68

用Delphi编写和调用DLL

用Delphi编写和调用DLL新建一个DLL工程先,再在工程中新建一个单元文件,在该文件中声明并实现你的加密与解密方法,在DLL中对字符串操作时,尽量使用PChar 。//Delphi(Pascal)...
  • cadenzasolo
  • cadenzasolo
  • 2016年03月16日 16:48
  • 258

Delphi调用C写的dll

一.用C语言写了一个Dll,编译成功。 是一个非常简单的加密算法,代码如下: #include __declspec(dllexport) void Encipher(char a[16])  ...
  • farrellcn
  • farrellcn
  • 2014年01月17日 20:10
  • 1411

Delphi 编写DLL动态链接库文件的知识和样例

一、DLL动态链接库文件的知识简介:                   Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝。动态链接库就是在这种情况下出现的。动态链接库不用重...
  • zang141588761
  • zang141588761
  • 2016年04月26日 10:10
  • 4877

Delphi7程序调用C#写的DLL解决办法(DLL)

近来,因工作需要,必须解决Delphi7写的主程序调用C#写的dll的问题。在网上一番搜索,又经过种种试验,最终证明有以下两种方法可行:     编写C#dll的方法都一样,首先在vs2005中创建...
  • zlwzlwzlw
  • zlwzlwzlw
  • 2015年02月10日 10:15
  • 2668

C/C++调用Delphi制作的dll时发现的一些问题

做了一个网络业务逻辑实体,是用C++编写的dll,内部有一个全局的业务实体,外部准备用Delphi编写的界面程序来控制并显示状态...... 1. C++的dll中不能用C++风格的导出方式:_dec...
  • gyymen
  • gyymen
  • 2016年12月09日 08:31
  • 1076

Delphi调用C++编写的动态链接库dll的方法

首先我们先看一下普通Delphi调用动态链接库dll的方法: {===================静态调用DLL函数===================} //首先声明这个DLL中的...
  • qq_22129035
  • qq_22129035
  • 2015年11月16日 11:48
  • 1513
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Delphi中高级DLL的编写和调用
举报原因:
原因补充:

(最多只允许输入30个字)