动态库的编写和调用 - Delphi

uDll.pas

function Add10(ANum: integer): integer; stdcall; //Delphi 默认采用 register 调用约定,如果dll涉及跨语言调用,最好

明确指出采用 stdcall 调用约定

library MyDll;

uses

ShareMem; // 如果dll 涉及长字符串的参数或变量,需要在 uses 第一的位置引用 ShareMem 单元。

exports

Add10;

可以使用标准指令以方便和加速过程、函数的调用。即 name,index,resident

Add10 name 'NewAdd'; //如果不写 name,默认以过程或函数最初声明的名称为准

Add10 index 1; //如果不写 index,默认编译器按顺序自动分配;index指令只对 windows 系统有用如果要同时使用 name 和 index ,那么 index 必须置于 name 前面

resident 主要为了向后兼容,编译器将忽略它

注意: exports 可以导出重载(overload)函数,但书写函数时必须加上参数。例如:

Add10(ANum: integer) name 'Add10_Int';

Add10(Anum: real) name 'Add10_Real'; //可以加一个 name 分别标示名称。 重载时一定不能用 index 指令

在 Widnows 32 位程序中,两个应用程序的地址空间是相互没有联系的。DLL 在内存中是一份拷贝(每个应用程序的进程空间各自拥有该 DLL 的一个副本及自身的一套全局变量),而变量是在各进程的地址空间中,因此不能借助 DLL 的全局变量来达到两个应用程序间的数据传递,除非使用内存映像文件。

调用 dll:

(1)静态调用

function Add10(ANum: integer): integer; stdcall; external 'MyDll.dll';

注意:

• 必须用 stdcall 作为调用参数。

• 大小写敏感。与 Delphi 程序不同,调用动态链接库是大小写敏感的

(2)动态调用

type

TAdd10 = function(ANum: integer): integer; stdcall;

const

MyDllName = 'MyDll.dll';

var

handle:THandle ;

FPointer: TFarProc;

MyFunc : TAdd10 ;

begin

handle := LoadLibrary(MyDllName); {装载 DLL 到内存}

if handle <> 0 then begin

try

FPointer := GetProcAddress(handle, 'Add10’); {获得函数的入口地址}

//@MyFunc := GetProcAddress(handle, 'Add10’);

//if @MyFunc <> nil then //也可以采用这种编写方式

if FPointer <> nil then begin

MyFunc := TAdd10(FPointer) ;

…………

end;

finally

FreeLibrary(handle); {释放 dll}

end;

end;

end;