跟着老侯玩编程 跟着老侯玩编程
首页
  • 基础语法
  • 设计模式
  • 基础语法
  • 课程目录
  • 码农宝典
网盘 (opens new window)
留言
首页
  • 基础语法
  • 设计模式
  • 基础语法
  • 课程目录
  • 码农宝典
网盘 (opens new window)
留言
  • 基础语法

    • 单元文件
    • 变量和常量
    • 内联变量
    • 基本数据类型
    • 复合数据类型
    • 语句(选择语句)
    • 语句(循环语句)
    • 数组
    • 初识例程
    • 初识面向对象
    • 属性Property
    • 面向对象的方法
    • 指针
    • 接口
    • 匿名函数和委托实现
    • 多态
    • 字符串详解
    • 异常处理
    • 反射机制
    • 泛型容器
    • JSON
    • 文件操作
    • Dll创建并调用
      • DLL文件搜索位置
      • 调用约定
        • DLL数据作用范围
        • 调用方式
      • 创建DLL
      • 改变项目的输出目录
      • 静态调用
      • 动态调用方式
      • 两种方式的优缺点
    • DLL初始化和退出处理
    • Package
    • 理解消息循环
    • VCL与Windows消息
    • 钩子原理
    • 进程通讯-内存映像
    • 多线程开篇
    • 线程控制
    • 线程同步
  • 设计模式

    • 单例模式
    • 单例模式二
    • 策略模式
    • 简单工厂模式
    • 建造者模式
    • 原型模式
    • 模板方法模式
    • 状态模式
    • 迭代器模式
    • 解释器模式
    • 责任链模式
    • 中介者模式
    • 备忘录模式
    • 命令模式
    • 观察者模式
    • 访问者模式
    • 适配器模式
    • 桥接模式
  • Delphi
  • 基础语法
舞动的代码
2022-05-05

Dll创建并调用

每个DLL文件都包含一个导出函数表,这些导出函数由他们的函数名或函数编号与外界联系起来,函数表中还包含了DLL中函数的地址,当应用程序加载DLL模块时,应用程序并不知道DLL中的调用函数的实际地址,只知道函数的名字或编号,系统在加载DLL模块时动态建立一个函数调用与函数地址的对应表,如果重新编译或者重建DLL文件,并不需要修改应用程序,除非改变了导出函数的名字或编号

# DLL文件搜索位置

如果不指定路径,Windows将遵循下面的搜索顺序来定位DLL

  • 包含EXE文件的目录
  • 进程的当前工作目录
  • Windows系统目录
  • 列在Path环境变量中的一系列目录

# 调用约定

调用约定,是指调用例程时参数的传递顺序。在Delphi中DLL支持的调用约定如下

调用约定 参数传递顺序
Register 从左到右
PASCAL 从左到右
Stdcall 从右到左
Cdecl 从右到左
safecall 从右到左

stdcall能保证不同语言写的DLL的兼容性,同时也是WindowsAPI的约定方式。

Delphi的默认调用方式为Register

Cdecl是采用C/C++的调用约定,适用于C++语言编写的DLL;

safecall是适合于声明ole对象中的方法

# DLL数据作用范围

DLL可以与其相连的多个进程共享数据、变量和分配的内存,对于每个相关的进程来说也可以有其专用的数据、变量和分配的内存。因而,用户可以以每个线程为依据存储数据,从而使一个线程的多个实例具有其专用的数据

DLL函数中的局部变量的作用范围限于定义的函数之中.DLL源代码中的全局变量对每一个与DLL相连的进程都是全局的

为了实现不同进程中的数据共享。可以使用内存映像文件、注册表或者文件的读写、全局钩子、声明一个共享数据段(只适用于Windows9X)、套接字、管道、远程过程调用等技术。 实际应用中推荐使用内存映像文件的方式实现数据共享

# 调用方式

  • 通过过程、函数名
  • 通过过程、函数的别名
  • 通过过程、函数的编号

# 创建DLL

uses
  Vcl.Dialogs,
  System.SysUtils,
  System.Classes;
{$R *.res}
//建立过程
procedure Test;
begin
  ShowMessage('TestDLL.Test');
end;

//建立函数,stdcall为参数入栈方式
function add(a, b: Integer): Integer;stdcall;
begin

  Result := a + b;
end;

//导出列表
exports
  Test name 'my01',
  add;

begin

end.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 改变项目的输出目录

将exe和dll文件输出到同一个目录中,项目目录结构如下:

├── Dll和主程序通讯(ProjectGroup)
    ├── bin
    └── 窗口程序(project)
    └── Dll程序(project)
1
2
3
4

具体步骤

选中项目(project)右击-->options-->Delphi Compiler-->Output Directory--->选择bin

# 静态调用

主程序在调用该DLL 时,首先在interface 部分声明要调用的函数:

//导出过程
procedure Test; external 'ProjectDll.dll';
//导出函数
function add(a, b: Integer): Integer;stdcall; external 'ProjectDll.dll';

procedure TForm1.btn1Click(Sender: TObject);
begin

  ShowMessage(add(10, 20).ToString);
end;

1
2
3
4
5
6
7
8
9
10
11

PS:在其他工程调用,如果不在一个工程组,需要在相同目录下、System32下或指定路径;声明可以在实现区或接口区,这里的函数名要一致,甚至大小写。

# 动态调用方式

dll代码

function sub(a, b: Integer): Integer; stdcall;
begin

  Result := a - b;
end;

exports
  sub;
1
2
3
4
5
6
7
8

interface部分声明

type
//定义一个函数类型,参数要和需要的函数一致
  sub1 = function(a, b: Integer): Integer; stdcall;

  TForm1 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
  private
    { Private declarations }
    MB: sub1;  {声明函数 MB}
    inst: LongWord;  {声明一个变量来记录要使用的 DLL 句柄}
  public
    { Public declarations }
  end;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

调用实现

procedure TForm1.btn2Click(Sender: TObject);
begin
  try
    //动态载入DLL ,并返回其句柄
    inst := LoadLibrary('ProjectDll.dll');
    if inst <> 0 then
    begin
      MB := GetProcAddress(inst, 'sub');
      ShowMessage(MB(30, 10).ToString);
    end;
  finally
    //记得释放
    FreeLibrary(inst);
  end;
end;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 两种方式的优缺点

静态方法实现简单,易于掌握并且一般来说稍微快一点,也更加安全可靠一些;

但是静态方法不能灵活地在运行时装卸所需的DLL,而是在主程序开始运行时就装载指定的DLL直到程序结束时才释放该DLL,另外只有基于编译器和链接器的系统(如Delphi)才可以使用该方法。

动态方法较好地解决了静态方法中存在的不足,可以方便地访问DLL中的函数和过程,甚至一些老版本DLL中新添加的函数或过程;

但动态方法难以完全掌握,使用时因为不同的函数或过程要定义很多很复杂的类型和调用方法。对于初学者,建议使用静态方法,待熟练后再使用动态调用方法。

上次更新: 2022/05/05, 14:24:28
文件操作
DLL初始化和退出处理

← 文件操作 DLL初始化和退出处理→

Theme by Vdoing | Copyright © 2013-2022 冀ICP备16006233号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×