tiDLL参数调用约定
—————————————————————— 数据挖掘实验室
令 传递顺序 参数删除
stdcall 从左到右 函数方面
cdecl 从右到左 调用方面
pascal 从左到右 函数方面
register 从左到右 函数方面 数据挖掘研究院
━━━━━━━━━━━━━━━━━━━━━━ 数据挖掘研究院
退出过程编译时必须关闭stack_checking,因而需设置编译指示 {$S-} 。 数据挖掘研究院
━━━━━━━━━━━━━━━━━━━━━ 数据挖掘研究院
//——————————dll的创建
brary mydll
{$S-} 数据挖掘研究院
//————————uses单元 数据挖掘研究院
uses
classes,stdsys, form in "form.pas"{form}; 数据挖掘实验室
//—————————变量声明 数据挖掘研究院
var 数据挖掘研究院
love:string;
baby:integer; 数据挖掘研究院
SaveExit: Pointer;
//—————————函数和过程
procedure myinnerproc();stdcall; //内部使用过程 数据挖掘研究院
begin
{添入代码} 数据挖掘研究院
end; 数据挖掘研究院
procedure myproc(var love:string);stdcall;export; //输出可以调用过程
begin
{添入代码} 数据挖掘实验室
end; 数据挖掘研究院
function myfunction(baby:integer):integer;stdcall;export;//可调用函数
begin
{添入代码} 数据挖掘研究院
end;
procedure LibExit; far;
begin 数据挖掘研究院
if ExitCode = wep_System_Exit then 数据挖掘实验室
begin 数据挖掘研究院
{ 系统关闭时的相应处理 }
end
else
begin 数据挖掘实验室
{ DLL卸出时的相应处理 } 数据挖掘实验室
end; 数据挖掘研究院
ExitProc := SaveExit; { 恢复原来的退出过程指针 } 数据挖掘研究院
end;
//——————————输出说明
exports 数据挖掘研究院
myproc name "myproc" index 1, 数据挖掘研究院
myfunction name "myfuntion" index 2 risdent;//输出信息始终保持在内存中{risdent}
//——————————初始化工作 数据挖掘研究院
begin 数据挖掘研究院
{DLL的初始化工作 }
SaveExit := ExitProc; { 保存原来的退出过程指针 }
ExitProc := @LibExit; { 安装新的退出过程 } 数据挖掘实验室
End.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 数据挖掘实验室
表10.1 ExitCode的取值与意义 :取 值 意 义
—————————————————————
WEP_System_Exit Windows关闭 数据挖掘研究院
WEP_Free_DLLx DLLs被卸出
━━━━━━━━━━━━━━━━━━━━━
//--------------调用dll
1。静态调用
在静态调用一个DLLs中的过程或函数时,external指示增加到过程或函数的声明语句中。
被调用的过程或函数必须采用远调用模式。这可以使用far过程指示或一个{$F +}编译指示。
Delphi全部支持传统Windows动态链接库编程中的三种调用方式,它们是:
● 通过过程/函数名
● 通过过程/函数的别名
● 通过过程/函数的顺序号 数据挖掘研究院
//————————————————————静态调用举例
unit windows 数据挖掘研究院
interface
function FindWindowsEx(Parent,Child:hwnd;classname,windowsname:pchar):hwnd;stdcall;
const
user32="user32.dll" 数据挖掘研究院
implementation 数据挖掘研究院
function FindWindowEx; external user32 name "FindWindowExA"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2. 动态调用
2.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,以保证不会有多余的库模块在应用程序结束后仍留在内存中。 数据挖掘研究院
//———————————— 动态调用举例 数据挖掘研究院
在利用GetProcAddess返回的函数指针时,必须进行强制类型转换:
Order := TInstr(PFunc)(text,Key);
TInStr是一个定义好了的函数类型: 数据挖掘研究院
type
TInStr = function(Source: PChar;Check: Char): Integer;
//--------------------------------- 数据挖掘研究院
procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char); 数据挖掘研究院
var
order: Integer; 数据挖掘研究院
txt: PChar;
PFunc: TFarProc;
Moudle: THandle;
begin
Moudle := Loadlibrary("c:dllsexample.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 := "不包含这个字符 "
end else
Label1.Caption := "位于第"+IntToStr(Order+1)+"位"; 数据挖掘实验室
Freelibrary(Moudle); 数据挖掘研究院
end;
//———————————— 用于实现数据传输的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是一个预定义的常数。
表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 数据挖掘研究院
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

