Delphi 动态链接库(一)
来源:互联网 发布:中国教育数据统计网 编辑:程序博客网 时间:2024/06/04 19:45
======================================================
注:本文源代码点此下载
======================================================
在下面的程序中我们把一个字符串操作的函数储存到一个dlls中,以便需要的时候调用它。应该注意的一点是:为了保证这个函数可以被其它语言编写的程序所调用,作为参数传递的字符串应该是无结束符的字符数组类型(即pchar类型),而不是object pascal的带结束符的srting类型。程序清单如下:
library example;
uses
sysutils,
classes;
{返回字符在字符串中的位置}
function instr(sourcestr: pchar;ch: char): integer; export;
var
len,i: integer;
begin
len := strlen(sourcestr);
for i := 0 to len-1 do
if sourcestr[i] = ch then
begin
result := i;
exit;
end;
result := -1;
end;
exports
instr index 1 name 'myinstr' resident;
begin
end.
10.2.2 调用dlls
有两种方法可用于调用一个储存在dlls中的过程。
1.静态调用或显示装载
使用一个外部声明子句,使dlls在应用程序开始执行前即被装入。例如:
function instr(sourcestr : pchar;check : char); integer; far; external'usestr';
使用这种方法,程序无法在运行时间里决定dlls的调用。假如一个特定的dlls在运行时无法使用,则应用程序将无法执行。
2.动态调用或隐式装载
使用windows api函数loadlibray和getprocaddress可以实现在运行时间里动态装载dlls并调用其中的过程。
若程序只在其中的一部分调用dlls的过程,或者程序使用哪个dlls, 调用其中的哪个过程需要根据程序运行的实际状态来判断,那么使用动态调用就是一个很好的选择。
使用动态调用,即使装载一个dlls失败了,程序仍能继续运行。
10.2.3 静态调用
在静态调用一个dlls中的过程或函数时,external指示增加到过程或函数的声明语句中。被调用的过程或函数必须采用远调用模式。这可以使用far过程指示或一个{$f +}编译指示。
delphi全部支持传统windows动态链接库编程中的三种调用方式,它们是:
● 通过过程/函数名
● 通过过程/函数的别名
● 通过过程/函数的顺序号
通过过程或函数的别名调用,给用户编程提供了灵活性,而通过顺序号(index)调用可以提高相应dll的装载速度。
10.2.4 动态调用
10.2.4.1 动态调用中的api函数
动态调用中使用的windows api函数主要有三个,即:loadlibrary,getprocaddress和freelibrary。
1.loadlibrary: 把指定库模块装入内存
语法为:
function loadlibrary(libfilename: pchar): thandle;
libfilename指定了要装载dlls的文件名,如果libfilename没有包含一个路径,则windows按下述顺序进行查找:
(1)当前目录;
(2)windows目录(包含win.com的目录)。函数getwindowdirectory返回这一目录的路径;
(3)windows系统目录(包含系统文件如gdi.exe的目录)。函数getsystemdirectory返回这一目录的路径;
(4)包含当前任务可执行文件的目录。利用函数getmodulefilename可以返回这一目录的路径;
(5)列在path环境变量中的目录;
(6)网络的映象目录列表。
如果函数执行成功,则返回装载库模块的实例句柄。否则,返回一个小于hinstance_error的错误代码。错误代码的意义如下表:
表10.2 loadlibrary返回错误代码的意义
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
错误代码意义
——————————————————————————————————————
0 系统内存不够,可执行文件被破坏或调用非法
2 文件没有被发现
3 路径没有被发现
5 企图动态链接一个任务或者有一个共享或网络保护错
6 库需要为每个任务建立分离的数据段
8 没有足够的内存启动应用程序
10 windows版本不正确
11 可执行文件非法。或者不是windows应用程序,或者在.exe映
像中有错误
12 应用程序为一个不同的操作系统设计(如os/2程序)
13 应用程序为ms dos4.0设计
14 可执行文件的类型不知道
15 试图装载一个实模式应用程序(为早期windows版本设计)
16 试图装载包含可写的多个数据段的可执行文件的第二个实例
19 试图装载一个压缩的可执行文件。文件必须被解压后才能被装裁
20 动态链接库文件非法
21 应用程序需要32位扩展
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
假如在应用程序用loadlibrary调用某一模块前,其它应用程序已把该模块装入内存,则loadlibrary并不会装载该模块的另一实例,而是使该模块的“引用计数”加1。
2.getprocaddress:捡取给定模块中函数的地址
语法为:
function getprocaddress(module: thandle; procname: pchar): tfarproc;
module包含被调用的函数库模块的句柄,这个值由loadlibrary返回。如果把module设置为nil,则表示要引用当前模块。
procname是指向含有函数名的以nil结尾的字符串的指针,或者也可以是函数的次序值。如果procname参数是次序值,则如果该次序值的函数在模块中并不存在时,getprocaddress仍返回一个非nil的值。这将引起混乱。因此大部分情况下用函数名是一种更好的选择。如果用函数名,则函数名的拼写必须与动态链接库文件exports节中的对应拼写相一致。
如果getprocaddress执行成功,则返回模块中函数入口处的地址,否则返回nil。
3.freelibrary:从内存中移出库模块
语法为:
procedure freelibrary(module : thandle);
module为库模块的句柄。这个值由loadlibrary返回。
由于库模块在内存中只装载一次,因而调用freelibrary首先使库模块的引用计数减一。如果引用计数减为0,则卸出该模块。
每调用一次loadlibrary就应调用一次freelibray,以保证不会有多余的库模块在应用程序结束后仍留在内存中。
10.2.4.2 动态调用举例
对于动态调用,我们举了如下的一个简单例子。系统一共包含两个编辑框。在第一个编辑框中输入一个字符串,而后在第二个编辑框中输入字符。如果该字符包含在第一个编辑框的字符串中,则标签框显示信息:“位于第n位。”,否则显示信息:“不包含这个字符。”。如图是程序的运行界面。
输入检查功能的实现在edit2的onkeypress事件处理过程中,程序清单如下。
procedure tform1.edit2keypress(sender: tobject; var key: char);
var
order: integer;
txt: pchar;
pfunc: tfarproc;
moudle: thandle;
begin
moudle := loadlibrary('c:\dlls\example.dll');
if moudle > 32 then
begin
edit2.text := '';
pfunc := getprocaddress(moudle,'instr');
txt := stralloc(80);
txt := strpcopy(txt,edit1.text);
order := tinstr(pfunc)(txt,key);
if order = -1 then
label1.caption := '不包含这个字符 '
else
label1.caption := '位于第'+inttostr(order+1)+'位';
end;
freelibrary(moudle);
end;
在利用getprocaddess返回的函数指针时,必须进行强制类型转换:
order := tinstr(pfunc)(text,key);
tinstr是一个定义好了的函数类型:
type
tinstr = function(source: pchar;check: char): integer;
10.3 利用dlls实现数据传输
10.3.1 dlls中的全局内存
windows规定:dlls并不拥有它打开的任何文件或它分配的任何全局内存块。这些对象由直接或间接调用dlls的应用程序拥有。这样,当应用程序中止时,它拥有的打开的文件自动关闭,它拥有的全局内存块自动释放。这就意味着保存在dlls全局变量中的文件和全局内存块变量在dlls没有被通知的情况下就变为非法。这将给其它使用该dlls的应用程序造成困难。
为了避免出现这种情况,文件和全局内存块句柄不应作为dlls的全局变量,而是作为dlls中过程或函数的参数传递给dlls使用。调用dlls的应用程序应该负责对它们的维护。
但在特定情况下,dlls也可以拥有自己的全局内存块。这些内存块必须用gmem_ddeshare属性进行分配。这样的内存块直到被dlls显示释放或dlls退出时都保持有效。
由dlls管理的全局内存块是应用程序间进行数据传输的又一途径,下面我们将专门讨论这一问题。
10.3.2 利用dlls实现应用程序间的数据传输
利用dlls实现应用程序间的数据传输的步骤为:
1. 编写一个dlls程序,其中拥有一个用gmem_ddeshare属性分配的全局内存块;
2. 服务器程序调用dlls,向全局内存块写入数据;
3. 客户程序调用dlls,从全局内存块读取数据。
10.3.2.1 用于实现数据传输的dlls的编写
用于实现数据传输的dlls与一般dlls的编写基本相同,其中特别的地方是:
1. 定义一个全局变量句柄:
var
hmem: thandle;
2. 定义一个过程,返回该全局变量的句柄。该过程要包含在exports子句中。如:
function getglobalmem: thandle; export;
begin
result := hmem;
end;
3. 在初始化代码中分配全局内存块:
程序清单如下:
begin
hmem := globalalloc(gmem_moveable and gmem_ddeshare,num);
if hmem = 0 then
messagedlg('could not allocate memory',mtwarning,[mbok],0);
end.
num是一个预定义的常数。
windows api函数globalalloc用于从全局内存堆中分配一块内存,并返回该内存块的句柄。该函数包括两个参数,第一个参数用于设置内存块的分配标志。可以使用的分配标志如下表所示。
表10.3 全局内存块的分配标志
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
标 志 意 义
—————————————————————————————————
gmem_ddeshare 分配可由应用程序共享的内存
gmem_discardable 分配可抛弃的内存(只与gmem_moveable连用)
gmem_fixed 分配固定内存
gmem_moveable 分配可移动的内存
gmem_nocompact 该全局堆中的内存不能被压缩或抛弃
gmem_nodiscard 该全局堆中的内存不能被抛弃
gmem_not_banked 分配不能被分段的内存
gmem_notify 通知功能。当该内存被抛弃时调用globalnotify函数
gmem_zeroinit 将所分配内存块的内容初始化为零
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
有两个预定义的常用组合是:
ghnd = gmem_moveable and gmem_zeroinit
gptk = gmem_fixed and gmem_zeroinit
第二个参数用于设置欲分配的字节数。分配的字节数必须是32的倍数,因而实际分配的字节数可能比所设置的要大。
由于用gmem_ddeshare分配的内存在分配内存的模块终止时自动抛弃,因而不必调用globalfree显式释放内存。
======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
- Delphi 动态链接库(一)
- Java与delphi动态链接库的数据交互(一)
- delphi DLL动态链接库
- 动态链接库(一)
- 动态链接库(一)
- 动态链接库(一)
- delphi中动态链接库dll的使用(转载)
- DELPHI 中动态链接库的使用
- delphi创建DLL动态链接库 [转贴]
- Delphi 制作 .dll 动态链接库
- delphi创建DLL动态链接库
- 专题:Windows动态链接库(一)
- C++动态链接库(一)
- 静态链接VS动态链接(一)
- 动态链接库详解【一】
- 动态链接库理解(一)
- 动态链接库与主程序交互之[MFC] VC++动态链接库资源调用(一)
- 动态链接库全面浅析(一)-----Win32 动态链接库
- 《Delphi 算法与数据结构》学习与感悟[4]: 关于 const
- Atlas—微软的Ajax工具包(来自MSDN Scott Guthrie)
- 读GI源码、学JS编程——Javascript动态加载技术。
- Delphi 中经常使用的正则表达式
- PHP动态网页转换HTML的一个简单办法
- Delphi 动态链接库(一)
- 初学标准布局应该理解HTML标签的语义
- Flash和HTML5那点事:后者拿什么取代Flash?
- 如何在SQLite中创建自增字段
- JAVA的Random类(转)
- Html 横向滚动栏
- 在Delphi中用XSLT转换xml文件格式
- 与Java Web Service相关的若干概念(JAX-WS,JAX-RS)
- 一个java技术人员这么说