Vous êtes sur la page 1sur 3

《现代电子技术》2003 年第 2 期总第 145 期 软件科技园

Bu ilder 中动态链接库的创建和调用
+ +
Borland C
邓 斌1 , 盛 文1 , 陈 玉2
( 11 空军雷达学院 湖北 武汉 430010; 21 玉林市骨科医院 广西 玉林 537000)

摘 要: 首先介绍了 Bo rland C + + B u ilder 中动态链接库的创建方法, 然后介绍了动态链接库的动态调用和静态调用


方法。
关键词: 动态链接库; C + + B u ilder; 动态调用; 静态调用
中图分类号: T P 31111     文献标识码: B      文章编号: 1004 373X ( 2003) 02 015 03

+ +
Crea t ing and L oad ing DLL Am ong Borland C Bu ilder
1 1 2
D EN G B in , SH EN G W en , CH EN Yu
(11 A ir Fo rce R adar A cadem y, W uhan, 430010, Ch ina; 21 Yu lin O rthop aedics Ho sp ital, Yu lin, 537000, Ch ina)

Abstract: In troduced how to crea te and load the dynam ic link lib ra ry1 A nd then it is p resen ted how to dynam ica lly load and
sta tica lly load a DLL du ring the run of a Bo rland C + + B u ilder app lica tion 1
Keywords: DLL ; C + + B u ilder; dynam ica lly load; sta tica lly load

互调用, DLL 方便了跨平台的软件开发, 提高了软件


1 引 言
的开发速度。本文针对 Bo rland C + + B u ilder 开发平台,
在 DO S 环境下, 程序员有时不得不编写完全相同 介绍了动态链接库 DLL 的创建和调用方法。
的代码并将其静态连接到不同的应用程序中, 这对于
2 动态链接库的创建
像 DO S 这样的单用户、单任务环境, 并不会造成多大
问题。 在 DO S 环境下, 所有的函数都是 “不可重入” 在 Bo rland C + + B u ilder ( 在下文中简称为 BCB ) 中
的, 包括 DO S 系统调用, 因为 DO S 总是假定在同一 动态链接库 DLL 的创建, 与标准 C + + 程序的创建基本
个时刻内存只有一个应用程序。 在 W indow s 环境下, 一样, 其包括以下步骤:
情况完全不同, 因为 W indow s 是一个多任务操作系 211 建立新的 DLL 工程, 生成 DLL 的程序框架
统, 同一个时刻可以有多个应用程序在运行, 这些应 ① 选择 F ile gN ew , 打开 N ew Item s 对话框;
用程序可能使用了完全相同的程序代码 ( 如写屏、 窗 ② 单击 DLL W iza rd 图标;
口移动和刷新) 。 如果像 DO S 那样使用静态连接, 那 ③ 选择主模块所使用的源程序语言 (C 或 C + + ) ;
么在同一个时刻, 就会出现同一段程序代码在内存的 ④ 如 果 想 要 DLL 的 进 入 点 是 DLLM a in、
不同地方存在相同的拷贝。 当系统运行了几个这样的 M SV C
+ +
类型, 可复选 V C + + 类型选项, 否则进入点为
程序, 内存资源很快就会枯竭。其实, 由于W indow s DLL En terPo in t;
是 GU I ( 图形用户界面) , 通常 W indow s 环境下的应 ⑤ 选中“U se V CL ”, 表示所创建 DLL 包含 V CL
用程序大量的代码是处理用户界面的, 对系统来说这 组件, 这一选项只在 C 源程序模块中才有效;
+ +

些操作是完全相同的, 因而不同应用程序会存在大量 ⑥ 如 果 需 要 DLL 为 多 线 程, 选 中 M u lt i


冗余代码。 T h readed 选项;
基于这个问题, W indow s 的设计者提出一种方 ⑦ 单击 O K 按钮, 将生成 DLL 的程序框架。
法, 即用动态链接库 DLL (D ynam ic L ink L ib ra ry ) 来 在 DLL 的 程 序 框 架 中, D llEn t ryPo in t 函 数 是
实现应用程序间代码共享 。DLL 可以用多种语言编 [1]
DLL 的入口方法, 该函数的原型声明如下:
写, 只要遵循一定规范, 不同语言编写的 DLL 可以相 in t W INA P ID llEn tryPo in t (H IN STAN CE h in st, un signed
long rea son, vo id 3 lpR eserved) ;
收稿日期: 2002 11 15 入口方法主要用来对 DLL 的初始化程序和卸载
15
© 1995-2004 Tsinghua Tongfang Optical Disc Co., Ltd. All rights reserved.
邓 斌等: Bo rland C + + B u ilder 中动态链接库的创建和调用

程序; 213  用“d llim po rt ”


描述 DLL 的出口函数
参数: h in st 用来指示 DLL 的基地址; rea son 用来 在上述的例程 M yDLL 1cpp 中, 出口函数的声明
指示 DLL 的调用方式, 用于区别多线程和单线程对 如下所示:
DLL 的调用、创建和卸载。 ex tern "C " d- eclsp ec (d llexpo rt) in t -s tdca ll PCop yF ile (cha r
3 sou r, cha r3 ta rg ) ;
212 在程序中加入用户所要创建的 DLL 函数
其中的 ex tern "C " 是代表 C 语言的规则来命名,
在如下的例程 M yDLL 1cpp 中用户创建的 DLL
而不要以 C + + 语言的规则命名, 因为 C + + 命名规则会
函数是:
在函数前面加上一些特殊名称, 而各种 C + + 编译器都
in t -stdca ll PCop yF ile (cha r 3 sou r, cha r 3 ta rg )
g g - - - - - - - - 例程 M yDLL 1cpp - - - - - - - 有 各 自 的 命 名 标 准, 这 将 造 成 调 用 上 的 困 扰, 而-
# include < vcl1h> declsp ec ( d llexpo rt ) 是表示要把此函数 expo rt 给其他
# include < fcn tl1h> 程序调用。- stdca ll 则是定义函数的参数传入方式, 一
# include < io 1h> 般 Cg
C 都是采用- stdca ll 的传入方式。
+ +

# include < sysg sta t 1h>


注意: 动态链接库中出口函数有不同的调用方式:
# include < std lib 1h>
c- decl、p- a sca l、- fa stca ll 和- stdca ll 等。 C B u ilder 中
+ +
# p ragm a hd rstop
ex tern "C " d- eclsp ec ( d llexpo rt ) in t -s tdca ll PCop yF ile ( cha r 3 默认的调用方式为- cdecl ( 可以省略不写) ; 但考虑兼
sou r, cha r 3 ta rg ) ; g
g出口函数的声明 容性, 一般使用- stdca ll 调用方式。
in t W INA P I D llEn tryPo in t ( H IN STAN CE h in st, un signed 214 DLL 工程的编译和连接
long rea son, vo id 3 )
最后, 运行菜单中的 P ro ject gB u ild A ll P ro ject 进
{
行 DLL 工程的编译和连接, 如果编译、连接成功, 将在
   retu rn 1;
} 当前工程的目录下生成 1d ll 文件, 同时生成该动态链
in t -s tdca ll PCop yF ile (cha r 3 sou r, cha r 3 ta rg ) 接库的接口库文件 1 lib。
g
g用户创建的 DLL 函数, 该函数功能为实现文件的复制;
{ 3 动态链接库的调用
   in t in, ou t, buf- len;
与其他 C + + 应用程序一样, C + + B u ilder 应用程序
  cha r 3 buf;
  buf = (cha r 3 ) m a lloc ( 1026) ; 同样可以很方便地使用 DLL 。在 DLL 中, 通常定义有
   if ( ( in = op en ( sou r, O - RDONL Y gO - B INA R Y, 2 种函数: 引出函数 ( expo rted funct ion ) 和内部函数
S - IR EAD ) ) = = - 1) ( in terna l funct ion ) 。 引出函数可以为外部模块所调
  { 用, 内部函数不能被外部模块调用, 而只能在他定义的
    ShowM essage ( " 无法打开源文件! ! " ) ;
DLL 内部调用。 本文所讨论的 DLL 的调用是指外部
     retu rn 1;
模 块对 DLL 中的引出函数的调用。 应用程序访问
  }
   if ( (ou t = op en ( ta rg, O - CR EA T gO - B INA R Y g DLL 中的引出函数有 2 种方式: 静态引入方式和动态
O - W RONL Y, S- IW R IT E ) ) = = - 1) 引入方式。
  { 311 静态引入方式
    ShowM essage ( " 无法打开源文件! ! " ) ; 所谓静态引入方式, 就是在编译连接阶段就已经
     retu rn 1;
确定了要调用的函数程序, 运行时就自动加载相应的
  }
动态链接库。 一直到程序结束前, 该 DLL 始终存在于
  w h ile ( ! eof ( in ) ) {
    buf- len= read ( in, buf, 1024) ; 内存中。
    w rite (ou t, buf, buf - len ) ; 首 先, 需 要 在 BCB 的 项 目 中 加 入 输 入 接 口 库
  } ( im po rt lib ra ry ) 。
  clo se ( in ) ; 打 开 工 程 项 目, 通 过 使 用 BCB V iew g P ro ject
  clo se (ou t ) ;
M anager“工程管理器”打开工程项目列表, 向工程中
  free (buf ) ;
   retu rn 0;
加入所要调用的 DLL 的接口库 ( 3 1 lib ) 。
} 其 次, 在 应 用 程 序 的 头 文 件 或 某 个 实 现 文 件
g g
- - - - - - - - - - - ( 1cpp ) 的开始处加入被调用函数的原型声明。
16
© 1995-2004 Tsinghua Tongfang Optical Disc Co., Ltd. All rights reserved.
《现代电子技术》2003 年第 2 期总第 145 期 软件科技园

例如: 某个工程中需要调用上述例程 M yDLL 中 明如下:


的函数, 其被调用函数的原型声明如下: FA R PRO C GetP rocA dd ress ( HM ODU L E hM odu le,
L PCSTR P rocN am e)
ex tern "C " d- eclsp ec (d llim po rt) in t -s tdca ll PCop yF ile (cha r
3 sou r, cha r3 ta rg ) ; M odu le 包含被调用函数库模块的句柄, 这个值由
注意: ①原型函数的调用方式声明应与 DLL 中出 L oadL ib ra ry 返回。 P rocN am e 表示函数名, 函数名的
口函数的调用方式声明保持一致; 如统一使用- stdca ll 拼写必须与动态链接库文件 EXPO R T S 节中的对应
调用方式。 ②利用 BCB 来创建的 DLL 都同时产生相 拼写一致。 该函数返回相应函数的函数指针。
应的输入接口库 ( im po rt lib ra ry ) , 对于第三方提供的 ( 3) F reeL ib ra ry 函数
DLL , 如 果 没 有 提 供 相 应 的 输 入 接 口 库 ( im po rt 该函数实现 DLL 的内存释放, 其原型声明如下:
lib ra ry ) , 可通过使用 BCB 的 im p lib 1exe 工具来获得; BOOL F reeL ib ra ry ( HM ODU L E hL ibM odu le)
其命令格式为: im p lib xxx 1 lib xxx 1d ll; 另外还可以使 M odu le 包含被调用函数库模块的句柄, 这个值由
用: t lib xxx 1 lib, xxx 1 lst 来获得 DLL 的内部函数列 L oadL ib ra ry 返回。每调用一次 L oadL ib ray 函数就应
表。 调用一次 F reeL ib ra ry 函数, 以保证在应用程序结束
312 动态引入方式 后不会有多余的库模块仍驻留在内存中。
静态引入方式实现简单且所需要编写的代码少,
4 结 语
因而许多用户可能偏爱这种方式, 但是他自身存在着
缺陷: ①如果要加载的 DLL 不存在, 或者 DLL 中没有 本文介绍了 C + + B u ilder 中动态链接库的创建和
所要引入的函数, 这时程序会自动终止运行, 使得在实 使用方法。 在具体使用中应注意: ①在进行多种语言
际情况中, 只有少数 DLL 不存在或少数函数出错, 就 编程时, 一定要注意在 DLL 调用中函数的调用方式应
会导致程序终止无法继续运行; ②DLL 在程序开始运 与创建时的出口函数的调用方式保持一致; ②创建
行时完成加载, 随后就一直驻留在内存中, 直到程序结 DLL 时编译链接时注意 P ro ject gO p t ion s 中的设置;
束退出才释放 DLL 。而采用动态引入方式可以解决上 在 Packages 选 项 卡 中, 去 除 B u ilder w ith run t im e
述问题。动态调用需要用到 3 个W indow s A P I 函数: p ackages 复 选 框; 在 L inker 选 项 卡 中, 去 除 U se
( 1) L oadL ib ra ry 函数 dynam ic R TL 复选框; 否则创建的 DLL 需要 R un t im e
该函数实现 DLL 的动态加载, 其原型声明如下: p ackages o r R un t im e lib ra ry 。
[3]

HM ODU L E L oadL ib ra ry ( L PCT STR L ibF ileN am e )


参 考 文 献
L ibF ileN am e 表示要加载的 DLL 的文件名;
假如在应用程序用 L oadL ib ra ry 调用某个模块 [ 1 ]  刘文圣 1C + + B u ilder 指南 [M ] 1 北京: 人民邮
前, 其 他 应 用 程 序 已 把 该 模 块 装 入 内 存, 则 电出版社, 19991413~ 4151
L oadL ib ra ry 并不会装载该模块的另一个实例, 而是 [ 2 ]  梁志刚 1C + + B u ilder510 开发人员指南 [M ] 1
使该模块的“引用计数” 加 1。 北京: 中国计量测机械工业出版社, 20001
( 2) GetP rocA dd ress 函数 [ 3 ]  常保平 1 在 C + + B u ilder 中调用M icroSoft DLL
该函数实现 DLL 中的函数指针的获取, 其原型声 [J ] 1 安阳师范学报, 20001

作者简介 邓 斌 武汉空军雷达学院新装备维修教研室。

   ( 上接第 14 页) [ 7 ]  齐国清 1 基于 D FT 相位的正弦波频率和初项的


[ 6 ]  刘渝 1 快速高精度正弦波频率估计综合算法 高 精度估计方法 [J ] 1 电子学报, 2001, 29
[J ] 1 电子学报, 1999, 27 ( 6) : 127~ 1281 ( 9) : 1164~ 11671

作者简介 陈迎春 女, 1979 年出生, 河南郑州人, 信息工程大学信息工程学院研究生, 软件无线电专业。


葛临东 男, 1946 年出生, 河南郑州人, 信息工程大学信息工程学院教授, 博士生导师, 主要研究方向: 软件无
线电。
17
© 1995-2004 Tsinghua Tongfang Optical Disc Co., Ltd. All rights reserved.

Vous aimerez peut-être aussi