一、使用 DEF 文件从 DLL 导出
模块定义或 DEF 文件 (*.def) 文件是文本文件,其中包含一个或多个描述 DLL 的各种特性的模块语句。 如果没有使用 __declspec(dllexport) 关键字来导出 DLL 的函数,则 DLL 需要 DEF 文件。
最小的 DEF 文件必须包含以下模块定义语句:文件中的第一个语句必须是 LIBRARY 语句。 此语句将 DEF 文件标识为属于 DLL。 LIBRARY 语句后跟 DLL 的名称。在VS配置 Project > Properties > Linker > Input > Module Definition File 添加该DEF文件。
EXPORTS 语句列出 DLL 导出的函数的名称和(可选)序号值。 可以通过在函数名称后加一个 at 符号 (@) 和一个数字,为函数分配序号值。 指定序号值时,它们必须在 1 到 N 的范围内,其中 N 是 DLL 导出的函数的数量。
案例
例如,包含用于实现链表的代码的 DLL LIST可能如下所示:
LIBRARY LIST
EXPORTS
Add @1
Delete @2
Modify @3
Find @4
二、使用 __declspec(dllexport) 从 DLL 导出
使用 __declspec(dllexport) 从 DLL 导出,可以使用 __declspec(dllexport) 关键字从 DLL 中导出数据、函数、类或类成员函数。
__declspec(dllexport) 将导出指令添加到对象文件中,因此你不需要使用 .def 文件。尝试导出已修饰的 C++ 函数名称时,这种便利性最为明显。 由于名称修饰没有标准规范,因此,导出函数的名称可能会因编译器版本而异。 如果你使 __declspec(dllexport),则只有在考虑到任何命名约定更改时,才需要重新编译DLL 和依赖 .exe 文件 。
许多导出指令只能在 .def 文件中创建,例如 ordinals、NONAME 和 PRIVATE,并且没有 .def 文件就无法指定这些属性。 不过,除了使用 .def 文件外还使用 __declspec(dllexport) 不会导致生成错误出现。
案例
若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左侧(如果指定了关键字的话)。
例如:
__declspec(dllexport) void __stdcall Funtion_Name(void);
若要导出类中的所有公共数据成员和成员函数,该关键字必须出现在类名的左侧,如下所示:
class __declspec(dllexport) CExampleExport : public CObject
{ ... class definition ... };
备注
__declspec(dllexport) 不能应用于采用 __clrcall 调用约定的函数。
生成 DLL 时,通常会创建一个包含要导出的函数原型和/或类的头文件,并将 __declspec(dllexport) 添加到头文件中的声明内。为了提高代码的可读性,请为 __declspec(dllexport) 定义宏,并对要导出的每个符号使用此宏:
#define DllExport __declspec( dllexport )