如有不对的请及时指正,共同学习
1.编译生成dll的时候通常会生成一个同名的lib库,lib库是在哪儿设置的才会生成的呢?
-
首先理解一个名称:lib库不单单是叫做静态链接库,它其实也叫做导入库。
-
生成dll的时候绝大多数情况下我们会生成对应的lib库,并且使用lib库是很常见的做法。导入库提供了方便的方式来链接 DLL,并在编译时让编译器自动处理函数的引用和解析。 导入库文件包含了对 DLL 中导出函数的符号信息,使得其他项目可以在编译时直接使用 DLL 中的函数,而不需要手动编写符号信息或进行额外的设置。
-
导入库在VS2019上面,可以在属性->链接器->高级-> 导入库进行设置,这边批注是重写导入库名称,其实就是我们常说的静态链接库名称。这也就是说在编译生成dll文件的同时,也会根据这个名称生成对应的lib文件。并且可以重新命名以及重新设置生成路径。
2.如果不使用lib,如何使用dll内导出函数?
-
首先一个前提:该函数必须是导出函数,也即是由__declspec(dllexport) 声明的函数,一般前面会再加一个 extern “C”。
- 示例代码:
// 导出函数的声明 extern "C" __declspec(dllexport) int AddNumbers(int a, int b); // 导出函数的定义 extern "C" __declspec(dllexport) int AddNumbers(int a, int b) { return a + b; }
- 加入extern "C"的目的:extern “C” 是用于指定在 C++ 中以 C 语言方式进行编译的指令。 当你将函数声明或定义标记为 extern "C"时,编译器会按照 C 语言的命名规则和函数调用约定来处理它们。因为 C++ 和 C 在名称修饰和函数调用约定上有所不同。对于导出到 DLL 的函数,如果你想确保其可被其他模块(包括 C 语言编写的模块)使用,通常需要使用 extern "C"修饰函数的声明和定义。简而言之,extern “C” 的作用是将 C++ 代码以 C 语言方式进行编译和导出,以确保与其他模块的交互性和兼容性。
-
两种使用方式:
-
手动编写导入声明:
-
在你的应用程序代码中,可以手动编写函数的导入声明,以便在编译时将其链接到 DLL 文件。
-
导入声明告诉编译器要在运行时从 DLL 文件中加载函数,而不是在链接时从导入库中解析函数。
-
示例代码:
extern "C" __declspec(dllimport) int AddNumbers(int a, int b); // 使用导入的函数 int result = AddNumbers(10, 20);
-
-
使用动态加载库:
-
动态加载库允许在运行时加载 DLL 文件,并根据需要动态链接其中的函数。
-
在你的应用程序中,你可以使用操作系统提供的函数(如 Windows 中的
LoadLibrary
和GetProcAddress
)来加载 DLL 文件并获取其中函数的地址。 -
示例代码:
HMODULE dllHandle = LoadLibrary("YourDll.dll"); if (dllHandle != NULL) { // 获取函数地址 typedef int (*AddNumbersFunc)(int, int); AddNumbersFunc addFunc = reinterpret_cast<AddNumbersFunc>(GetProcAddress(dllHandle, "AddNumbers")); if (addFunc != NULL) { // 调用函数 int result = addFunc(10, 20); } // 卸载 DLL 文件 FreeLibrary(dllHandle); }
-
-
3.dll与lib的关系
DLL 用于应用程序在运行时动态加载和使用代码,而 LIB 用于在编译时将其他模块与 DLL 进行链接,并解析其中的函数和符号。 DLL 提供了更大的灵活性和可扩展性,而 LIB 则允许在编译时静态地将代码连接到应用程序中。
4.使用lib库的时候,需要将对应的dll使用到的lib库加进来吗?
是的。当你使用一个 lib 库时,你需要链接器能够找到它所依赖的其他库。 这意味着你需要将所有必要的 lib 文件提供给链接器,以便正确地解析和链接所有的符号和函数。
5.如何正确的在程序中加载dll,需要注意什么?
为了能够正确使用 DLL 中的函数,你需要在编译时使用导入库(lib 文件)提供函数的符号信息,并在运行时确保相应的 DLL 文件能够被加载到内存中。 二者缺一不可,这样应用程序才能够调用和使用 DLL 中的函数。
5.通常的一个写法
#ifdef SSMATH_EXPORTS
#define SSMATH_API __declspec(dllexport)
#else
#define SSMATH_API __declspec(dllimport)
#endif
使用方式:
-
本身代码文件,在预编译头里面#define SSMATH_EXPORTS。这样直接使用SSMATH_API放置在函数前面。标识这个函数是导出函数。
-
其他代码文件,预编译头不加该定义。则标识导入该函数。
-
这只是一种比较规范的写法,当然如果仅仅在本身代码文件的导出函数前面声明了__declspec(dllexport),也是没问题的。其他代码文件依旧可以导入该函数。