将公共符号导入应用程序或从 DLL 导出函数

⌚Time: 2023-09-24 21:15:20

👨‍💻Author: Jack Ge

资料来自MSDN

导入和导出

可以使用两种方法将公共符号导入应用程序或从 DLL 导出函数:

使用 .def 文件

模块定义 (.def) 文件是文本文件,其中包含一个或多个描述 DLL 的各种特性的模块语句。 如果没有使用 __declspec(dllimport) 或 __declspec(dllexport) 来导出 DLL 的函数,则 DLL 需要 .def 文件。

可以使用 .def 文件导入到应用程序中或从 DLL 导出。

使用 __declspec

正确编译代码不需要使用 __declspec(dllimport),但是这样做可以让编译器生成更优质的代码。 编译器能够生成更好的代码,因为它可以确定某个函数是否存在于 DLL 中,这使编译器生成的代码可以跳过在跨越 DLL 边界的函数调用中通常存在的间接级别。 不过,必须使用 __declspec(dllimport) 来导入 DLL 中使用的变量。

对于正确的 .def 文件 EXPORTS 部分,__declspec(dllexport) 是不需要的。 添加 __declspec(dllexport) 是为了提供一种简单的方法,可以在不使用 .def 文件的情况下从 .exe 或 .dll 文件导出函数。

Win32 可移植可执行文件格式旨在最大程度减少修复导入所必须涉及的页数。 为此,它将任何程序的所有导入地址都放置在一个名为导入地址表的位置。 这使加载程序可以在访问这些导入时仅修改一页或两页。

使用 __declspec(dllimport) 导入到应用程序中

使用由 DLL 定义的公共符号的程序会导入它们。 在为使用 DLL 生成的应用程序创建头文件时,请在公共符号的声明中使用 __declspec(dllimport)。 无论使用 .def 文件还是 __declspec(dllexport) 关键字进行导出,都可以使用关键字 __declspec(dllimport)。

为了提高代码的可读性,请为 __declspec(dllimport) 定义宏,并使用此宏来声明导入的每个符号:


#define DllImport   __declspec( dllimport )



DllImport int  j;

DllImport void func();

虽然在函数声明中使用 __declspec(dllimport) 是可选的,但如果你使用此关键字,编译器会生成更高效的代码。 不过,必须对导入的可执行文件使用 __declspec(dllimport),以访问 DLL 的公共数据符号和对象。 请注意,DLL 的用户仍需要与导入库链接。

可以对 DLL 和客户端应用程序使用相同的头文件。 为此,请使用特殊的预处理器符号来指示是生成 DLL 还是生成客户端应用程序。 例如:


#ifdef _EXPORTING

   #define CLASS_DECLSPEC    __declspec(dllexport)

#else

   #define CLASS_DECLSPEC    __declspec(dllimport)

#endif



class CLASS_DECLSPEC CExampleA : public CObject

{ ... class definition ... };

从 DLL 导出

DLL 文件的布局与 .exe 文件非常相似,但有一个重要的区别:DLL 文件包含导出表。 导出表包含 DLL 导出到其他可执行文件的每个函数的名称。 这些函数是进入 DLL 中的入口点;只有导出表中的函数才能被其他可执行文件访问。 DLL 中的任何其他函数都是 DLL 的私有函数。 可通过使用带有 /EXPORTS 选项的 DUMPBIN 工具来查看 DLL 导出表。

可使用两种方法从 DLL 导出函数:

用任一方法导出函数时,请确保使用 __stdcall 调用约定。