C++动态调用动态链接库(DLL或SO)的方法实现
作者:麦克斯.李
动态链接库是一种Windows操作系统下常见的可执行文件格式,它包含了一些可被其他应用程序调用的函数和数据,本文主要介绍了C++动态调用动态链接库(DLL或SO),感兴趣的可以了解一下
动态库调用流程大致可以描述为:0.创建动态库 -> 1.加载动态库 -> 2.定义函数类型 -> 3.获取函数地址 -> 4.调用函数 -> 5.卸载动态库。
这个流程和逻辑可以在不同的操作系统和编译器下略有差异,因此需要根据特定的平台和工具链做适当的调整。
0.创建动态库:
创建一个接口,并生成可供其他程序使用的DLL和SO(动态链接库),步骤如下:
要创建一个接口,并生成可供其他程序使用的DLL和SO(动态链接库),可以按照以下步骤进行:
- 创建接口头文件(例如
helloFunc.h
):在头文件中定义接口的函数和数据结构。将接口的所有公共部分放在这个头文件中,并确保使用适当的导出声明。
// helloFunc.h #ifdef _MSC_VER // Windows环境下的导出声明 #ifdef helloFunc_EXPORTS #define HELLOFUNC_API __declspec(dllexport) #else #define HELLOFUNC_API __declspec(dllimport) #endif #else // Linux/Unix下的导出声明 #ifdef HELLOFUNC_EXPORTS #define HELLOFUNC_API __attribute__((visibility("default"))) #else #define HELLOFUNC_API #endif #endif // 接口函数 #ifdef __cplusplus extern "C" { #endif HELLOFUNC_API void hello(); #ifdef __cplusplus } #endif
- 实现接口函数的源文件(例如
helloFunc.cpp
):在源文件中实现接口函数。确保使用正确的导出声明,并根据需要处理接口的具体逻辑。
// helloFunc.cpp #include "helloFunc.h" void hello() { // 实现函数逻辑 // ... }
- 生成 DLL 和 SO:
- 在Windows环境下,可以使用 Visual Studio 或 MinGW 等工具来生成 DLL 文件。将接口头文件和实现源文件添加到工程中,并设置导出选项,编译工程以生成 DLL 文件。
- 在Linux/Unix环境下,可以使用 GCC 或 Clang 等编译器来生成 SO 文件。将接口头文件和实现源文件编译成目标文件,然后使用编译器的特定选项和命令来将目标文件链接成 SO 文件。
1. 加载动态库:
使用操作系统提供的函数(如LoadLibrary()
、dlopen()
)加载动态库文件。需要指定动态库的文件路径或名称。
#if defined (WIN32) | defined (WIN64) HMODULE handle = nullptr; // 动态库句柄 #else void* handle = nullptr; // 动态库句柄 #endif // 加载动态库 #if defined (WIN32) | defined (WIN64) handle = LoadLibrary("example.dll"); // 在Windows中使用 #else handle = dlopen("libexample.so", RTLD_LAZY); // 在Linux/Unix中使用 #endif if (!handle) { #if defined (WIN32) | defined (WIN64) std::cerr << "无法加载动态库: " << GetLastError() << std::endl; // 在Windows中使用 #else std::cerr << "无法加载动态库: " << dlerror() << std::endl; #endif return 1; }
2. 函数类型定义:
使用函数指针来定义函数的类型,以便在动态库中找到的函数能够正确地调用。函数指针的类型必须与函数的签名(参数类型和返回类型)匹配。
void (*helloFunc)(); // 函数指针
3. 获取函数地址:
通过使用操作系统提供的函数(如GetProcAddress()
、dlsym()
)获取特定函数的地址。需要指定要调用的函数的名称。
// 获取函数地址 #if defined (WIN32) | defined (WIN64) helloFunc = (void (*)())GetProcAddress(handle, "hello"); // 在Windows中使用 #else helloFunc = (void (*)())dlsym(handle, "hello"); // 在Linux/Unix中使用 #endif if (helloFunc == nullptr) { #if defined (WIN32) | defined (WIN64) std::cerr << "无法找到函数: " << GetLastError() << std::endl; // 在Windows中使用 FreeLibrary(handle); // 在Windows中使用 #else std::cerr << "无法找到函数: " << dlerror() << std::endl; dlclose(handle); // 在Linux/Unix中使用 #endif return 1; }
4. 调用函数:
通过调用函数指针,实现对动态库中函数的调用。根据函数的参数类型和返回类型,在适当的位置传递参数,并根据需要处理返回值。
// 调用函数 helloFunc();
5. 卸载动态库:
使用操作系统提供的函数(如FreeLibrary()
、dlclose()
)卸载已加载的动态库。通常在不再需要动态库时执行这个步骤。
// 卸载动态库 #if defined (WIN32) | defined (WIN64) FreeLibrary(handle); // 在Windows中使用 #else dlclose(handle); // 在Linux/Unix中使用 #endif
6.总结
- helloFunc.h
// helloFunc.h #ifdef _MSC_VER // Windows环境下的导出声明 #ifdef helloFunc_EXPORTS #define HELLOFUNC_API __declspec(dllexport) #else #define HELLOFUNC_API __declspec(dllimport) #endif #else // Linux/Unix下的导出声明 #ifdef HELLOFUNC_EXPORTS #define HELLOFUNC_API __attribute__((visibility("default"))) #else #define HELLOFUNC_API #endif #endif // 接口函数 #ifdef __cplusplus extern "C" { #endif HELLOFUNC_API void hello(); #ifdef __cplusplus } #endif
- helloFunc.cpp
// helloFunc.cpp #include "helloFunc.h" void hello() { // 实现函数逻辑 // ... }
- main.cpp
#include <iostream> #if defined (WIN32) | defined (WIN64) #include <windows.h> // 在Windows中使用 #else #include <dlfcn.h> // 在Linux/Unix中使用 #endif int main() { #if defined (WIN32) | defined (WIN64) HMODULE handle = nullptr; // 动态库句柄 #else void* handle = nullptr; // 动态库句柄 #endif // 1. 加载动态库 #if defined (WIN32) | defined (WIN64) handle = LoadLibrary("example.dll"); // 在Windows中使用 #else handle = dlopen("libexample.so", RTLD_LAZY); // 在Linux/Unix中使用 #endif if (!handle) { #if defined (WIN32) | defined (WIN64) std::cerr << "无法加载动态库: " << GetLastError() << std::endl; // 在Windows中使用 #else std::cerr << "无法加载动态库: " << dlerror() << std::endl; #endif return 1; } // 2. 函数类型定义 void (*helloFunc)(); // 函数指针 // 3. 获取函数地址 #if defined (WIN32) | defined (WIN64) helloFunc = (void (*)())GetProcAddress(handle, "hello"); // 在Windows中使用 #else helloFunc = (void (*)())dlsym(handle, "hello"); // 在Linux/Unix中使用 #endif if (helloFunc == nullptr) { #if defined (WIN32) | defined (WIN64) std::cerr << "无法找到函数: " << GetLastError() << std::endl; // 在Windows中使用 FreeLibrary(handle); // 在Windows中使用 #else std::cerr << "无法找到函数: " << dlerror() << std::endl; dlclose(handle); // 在Linux/Unix中使用 #endif return 1; } // 4. 调用函数 helloFunc(); // 5. 卸载动态库 #if defined (WIN32) | defined (WIN64) FreeLibrary(handle); // 在Windows中使用 #else dlclose(handle); // 在Linux/Unix中使用 #endif return 0; }
到此这篇关于C++动态调用动态链接库(DLL或SO)的文章就介绍到这了,更多相关C++动态调用动态链接库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!