Delphi5实现DLL的编写、调用

效果图

在这里插入图片描述

显式跟隐式调用差不多的,就重新画了窗体,画的有点粗糙。

在这里插入图片描述

DLL文件

DLL文件是一种包含了可执行代码的库文件,但它不能独立运行,必须由其他程序(如EXE文件)显式或隐式地加载并调用。DLL文件通常用于实现代码的复用、模块化以及跨语言调用等功能。

如何理解跨语言调用?

在不同编程语言之间调用彼此的函数、过程或对象等代码单元的能力。这种机制允许开发者在混合编程环境中充分利用各种编程语言的优势,实现功能的整合与扩展。
开发者可以将特定功能的代码编译成DLL文件,然后在其他语言编写的程序中通过特定的调用机制(如LoadLibrary和GetProcAddress在Windows上)来加载和调用DLL中的函数。

DLL文件的创建

  1. 新建DLL项目:在Delphi5的IDE中,选择“File”->“New”->“Others…”,然后在弹出的对话框中选择“DLL Wizard”或直接在“Project”菜单下选择“New”->“DLL”,点击“OK”按钮创建一个新的DLL项目。
    在这里插入图片描述

  2. 编写代码:在DLL项目中,可以编写函数、过程等代码,这些代码将被编译到DLL文件中。需要注意的是,DLL中的函数和过程需要使用特定的调用约定(如stdcall、cdecl等),以确保它们能被其他程序正确调用。

library Project2;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  SysUtils,
  Classes;

{$R *.RES}

{定义函数时使用的调用约定,如果程序员希望自己的DLL库函数能够被其他程序设计语言的程序调用,应使用stdcall调用约定。}
function Max(x,y,z:Integer):Integer;stdcall;
var
  t:Integer;
begin
  if x>y then
    t:=x
  else
    t:=y;

  if t<z then
    t:=z;

  Result:=t;
end;

function Min(x,y,z:Integer):Integer;stdcall;
var
  t:Integer;
begin
  if x<y then
    t:=x
  else
    t:=y;

  if t>z then
    t:=z;

  Result:=t;
end;

{DLL的过程和函数想要在外部被使用,要用exports语句声明供其他应用程序调用的函数和过程名}
exports
  Max,Min;

begin
end.
  1. 导出函数和过程:在DLL项目的源代码中,需要使用exports语句来导出希望被其他程序调用的函数和过程。只有被导出的函数和过程才能在DLL被加载后,通过GetProcAddress等函数被其他程序获取其地址并调用。

  2. 编译DLL:编写并导出完所需的函数和过程后,就可以编译DLL项目了。编译成功后,将生成一个DLL文件,该文件可以被其他程序加载并调用其中的函数和过程。
    在这里插入图片描述

在这里插入图片描述

DLL文件的调用

隐式调用DLL

静态调用:在Delphi5的源代码中,使用external指示字列出要从DLL中调用的例程。这种方式需要在应用程序开始执行前就将DLL装入内存,并在单元的interface部分用external指示字列出要从DLL中调用的例程。但是,静态调用的缺点是程序在启动时如果找不到DLL将无法运行。

unit Unit1;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Dialogs, Forms,Form, Formprpt, StdCtrls;

type
  TForm1 = class(MForm)
    grp1: TGroupBox;
    edt1: TEdit;
    Edit1: TEdit;
    edt2: TEdit;
    lbl1: TLabel;
    lbl2: TLabel;
    lbl3: TLabel;
    Label1: TLabel;
    lbl4: TLabel;
    edt3: TEdit;
    btn1: TButton;
    btn2: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

  {静态载入在这声明
  隐式调用又称静态调用或装载时调用,对应于DLL的静态载入。
  要在应用程序中隐式调用某个动态链接库中的函数,
  一般要用external语句声明要调用的过程或函数及其所在的DLL文件名。}
  function Max(x,y,z:integer):integer;stdcall;external 'Project2.dll';
  function Min(x,y,z:integer):integer;stdcall;external 'Project2.dll';

implementation

{$R *.DFM}

procedure TForm1.btn1Click(Sender: TObject);
var
  x,y,z,max_v:Integer;
begin
  x:=StrToInt(edt1.text);
  y:=StrToInt(edit1.text);
  z:=StrToInt(edt2.text);
  max_v:=Max(x,y,z);
  edt3.Text:=IntToStr(max_v);
end;

procedure TForm1.btn2Click(Sender: TObject);
var
  x,y,z,min_v:Integer;
begin
  x:=StrToInt(edt1.text);
  y:=StrToInt(edit1.text);
  z:=StrToInt(edt2.text);
  min_v:=Min(x,y,z);
  edt3.Text:=IntToStr(min_v);
end;

end.

显式调用DLL

动态调用:使用Windows API函数LoadLibraryGetProcAddress来实现在运行时间里的动态装载DLL,并调用其中的过程。这种方式可以在需要时才加载DLL,避免了静态调用中可能出现的问题。同时,动态调用还能处理找不到DLL或在装入过程中出错的情况,提高了程序的健壮性。

unit Unit3;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Dialogs, Forms,Form, Formprpt, StdCtrls;

type
  TForm1 = class(MForm)
    grp1: TGroupBox;
    edt1: TEdit;
    edt2: TEdit;
    edt3: TEdit;
    edt4: TEdit;
    btn1: TButton;
    btn2: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{动态调用DLL}
type
  TintFunction = Function(x,y,z:Integer):Integer;stdcall;

var
  x,y,z:Integer;
  
{$R *.DFM}

{定义一个模板,这样只需要把函数名传给这里,就能调用函数了}
Function Calculate(FunName:PChar):Integer;
var
  DllName:string;
  Hinst:THandle;
  ProcName:PChar;
  Fpointer:TFarProc;
  Myfunc:TintFunction;
begin
  GetDir(0,DllName);//当前目录
  DllName:=DllName+'\Project2.dll'; //获取DLL文件名
  ProcName:=FunName; //函数名
  Hinst:=SafeLoadLibrary(DllName); //加载DLL文件
  if Hinst>0 then
  try
    Fpointer:=GetProcAddress(Hinst,ProcName);  //获得API函数的地址,放到指针那
    if Fpointer<>nil then
    begin
      Myfunc:=TintFunction(Fpointer);   //获取该地址的函数名
      Result:=Myfunc(x,y,z);   //运行函数获得结果
    end
    else
    ShowMessage('需要的函数不存在');
  finally
    FreeLibrary(Hinst);
  end
  else
  ShowMessage(DllName+'文件不存在');
end;

//点击按钮调用DLL库函数
procedure TForm1.btn1Click(Sender: TObject);
var
  Funname:PChar;
  Res:Integer;
begin
  Funname:='Max';
  x:=StrToInt(edt1.text);
  y:=StrToInt(edt2.text);
  z:=StrToInt(edt3.text);
  Res:=Calculate(Funname);
  edt4.Text:=IntToStr(Res);
end;

procedure TForm1.btn2Click(Sender: TObject);
var
  Funname:PChar;
  Res:Integer;
begin
  Funname:='Min';
  x:=StrToInt(edt1.text);
  y:=StrToInt(edt2.text);
  z:=StrToInt(edt3.text);
  Res:=Calculate(Funname);
  edt4.Text:=IntToStr(Res);
end;

end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值