一作用
DLL中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport),这里不再举例说明;另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。
在链接器阶段可以使用 /DEF(指定模块定义文件)链接器选项调用 .def 文件。如果生成的 .exe 文件没有导出,使用 .def 文件将使输出文件较大并降低加载速度。
二原因
在VC++中,生成DLL可以不使用.def文件。只需要在VC++的函数定义前要加__declspec(dllexport)修饰就可以了。但是使用__declspec(dllexport)和使用.def文件是有区别的。如果DLL是提供给VC++用户使用的,你只需要把编译DLL时产生的.lib提供给用户,它可以很轻松地调用你的DLL。但是如果你的DLL是供其他程序如VB、delphi,以及.NET用户使用的,那么会产生一个小麻烦。因为VC++对于__declspec(dllexport)声明的函数会进行名称转换,如下面的函数:
__declspec(dllexport) int __stdcallIsWinNT()
会转换为[email protected],这样你在VB中必须这样声明:
Declare Function IsWinNT Lib "my.dll" Alias "[email protected]" () As Long
@的后面的数由于参数类型不同而可能不同。这显然不太方便。所以如果要想避免这种转换,就要使用.def文件方式。
EXPORTS后面的数可以不给,系统会自动分配一个数。对于VB、PB、Delphi用户,通常使用按名称进行调用的方式,这个数关系不大,但是对于使用.lib链接的VC程序来说,不是按名称进行调用,而是按照这个数进行调用的,所以最好给出。
三 使用
例1:我们用VC6.0制作一个dll(动态链接库),不使用.def文件,在头文件中这样写
#ifndef LIB_H
#define LIB_H extern "C" int _declspec(dllexport)add(int x,int y);
#endif
如果是.def文件,可以这样 LIBRARY "xxx_dll" EXPORTS add PRIVAT
例2:首先创建 一个DLL程序,.cpp中
int __stdcall Sub(int numa, int numb)
{
return (numa - numb);
}
然后创建一个.def的文件,在里面加上
;DllTestDef.lib : 导出DLL函数
;作者:----
LIBRARY DllTestDef
EXPORTS
Add @ 1
Sub @ 2
最后创建一个测试程序:.cpp文件如下:
#include <iostream>
#include <windows.h>
using namespace std;
typedef int (__stdcall *FUN)(int, int);
HINSTANCE hInstance;
FUN fun;
int main()
{
hInstance =
LoadLibrary("DLLTestDef.dll");
if(!hInstance)
cout <<
"Not Find this Dll" << endl;
fun = (FUN)GetProcAddress(hInstance,
MAKEINTRESOURCE(1));
if (!fun)
{
cout
<< "not find this fun" << endl;
}
cout << fun(1, 2) <<
endl;
FreeLibrary(hInstance);
return 0;
}
说明:
.def文件的规则为:
(1)LIBRARY语句说明.def文件相应的DLL;
(2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);
(3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。
模块定义文件.def