vs2019生成dll并调用的实现示例:https://www.jb51.net/article/179759.htm
1. VS 中生成动态链接库的三种方式(导出函数)
开发环境:VS2019
创建动态链接库项目
新建项目,搜索 DLL ,选择 “ 具有导出项的(DLL)动态链接库 ”,
输入项目名称,选择项目所在目录,然后点击 创建
生成如下图所示的文件结构:
导出动态链接库
方法一 :声明导出
1、以 C++ 的方式声明导出。
在 CPP_DLL.cpp 文件中添加下面的函数,在函数声明前添加 _declspec(dllexport)
// C++ 的方式声明导出
_declspec(dllexport) int addFunc(int a, int b);
int addFunc(int a, int b)
{
return a + b;
}
示例截图:
2、以 C 的方式声明导出。
在 CPP_DLL.cpp 文件中添加下面的函数,在函数声明前添加 extern "C" _declspec(dllexport)
// C 的方式声明导出
extern "C"
{
_declspec(dllexport) int subFunc(int a, int b);
int subFunc(int a, int b)
{
return a + b;
}
}
示例截图:
然后点击 “ 生成解决方案 ” ,就可以在工程目录的 debug 目录或者 release 目录下(这取决你生成的是debug版本还是release版本)生成了动态链接库的相关文件。第三方调用时关键的文件为 .lib文件 和 .dll文件 以及工程目录下的 .h头文件 。
方法二: 模块定义文件导出
在项目中定义CPP_DLL.def 文件,该文件为模块导出文件
在 CPP_DLL.cpp 文件中添加下面的函数
LIBRARY
EXPORTS
mulFunc
divFunc
示例截图:
如果是 VS 平台,必须要在 连接器 中添加 .def 文件
然后点击 “ 生成解决方案 ” ,就可以在工程目录的 debug 目录或者 release 目录下(这取决你生成的是debug版本还是release版本)生成了动态链接库的相关文件。第三方调用时关键的文件为 .lib文件 和 .dll文件 以及工程目录下的 .h头文件 。
对应 的 DLL 和 lib 文件
2. 调用前面开发的动态链接库
1. 新建一个C/C++项目(test)
2. 将第三方库的 .h文件、.lib文件、.dll文件 复制进工程项目中
.dll文件是程序运行需要载入的动态链接库,VS中调试时可以通过 项目->属性->调试->环境 栏目添加.dll文件的 path 而成功调试,但在独立运行.exe程序是须将.dll文件放到同一目录下。
因此建议直接将 .dll文件。.h头文件 和 .lib库文件,只要是能够通过路径找到即可,为了方便管理,建议建立文件夹,放置在项目目录下。
3. 在项目中调用第三方库
有三种方法可以调用第三方库。
(1)直接在代码前添加引用
因为直接引用 CPPDLL.h 头文件,所以需要把 动态链接库的 函数声明放在头文件中。
修改 CPP_DLL 的 .h 文件 和 cpp 文件,把 函数 声明放在 .h 中,函数定义放在 cpp 文件中。
CPP_DLL.h
// C++ 的方式声明导出
_declspec(dllexport) int addFunc(int a, int b);
// C 的方式声明导出
extern "C"
{
_declspec(dllexport) int subFunc(int a, int b);
}
int mulFunc(int a, int b);
double divFunc(double a, double b);
CPP_DLL.cpp
int addFunc(int a, int b)
{
return a + b;
}
int subFunc(int a, int b)
{
return a - b;
}
// def 文件形式
int mulFunc(int a, int b)
{
return a * b;
}
double divFunc(double a, double b)
{
return a / b;
}
重新生成 DLL 文件,并将 DLL 、lib 、.h 文件拷贝到对应目录
C++ 测试代码:
#include <iostream>
#include "./CPP_DLL.h" //通过相对路径或绝对路径添加头文件
#pragma comment (lib,"./CPPDLL.lib") // 添加 lib 文件
int main()
{
std::cout << "Hello World!\n";
std::cout << addFunc(1, 2) << std::endl;
std::cout << subFunc(3, 4) << std::endl;
std::cout << mulFunc(5, 6) << std::endl;
std::cout << divFunc(7, 8) << std::endl;
}
运行结果截图:
(2)在解决方案管理面板中添加头文件和资源文件
添加一个现有项头文件,在文件夹中找到第三方库的头文件( CPP_DLL.h ),添加进新建立的项目。
添加一个现有项资源文件,在文件夹中找到第三方库的库文件( CPPDLL.lib ),添加进新建立的项目。
(3)在 项目属性 -> 设置 中 添加 头文件 和 库文件
- 项目->属性->VC++目录->包含目录 中添加第三方库的头文件;
- 库目录 下 添加 第三方库 的库文件(.lib文件)。
- 项目->属性->链接器->输入->附加依赖项中输入库文件名称。
在函数中调用第三方库中的函数
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
std::cout << addFunc(1, 2) << std::endl;
std::cout << subFunc(3, 4) << std::endl;
std::cout << mulFunc(5, 6) << std::endl;
std::cout << divFunc(7, 8) << std::endl;
}
4. 直接在代码里 load 动态库dll文件即可
这种方法不需要 include .h文件,不需要添加 lib库 和 lib库路径,
- 引入 windows.h(必须)
- 在 main 函数写下列语句调用 dll
因为 C++ 声明 的 动态链接库会发生 Name Mangling,导致 编译后的函数名字会发生变化,所以需要使用 工具 查看 编译编译后的 动态链接库 对应的函数名。
而 extern "C" 声明的 和 def 文件声明的,编译后的函数名不会发生变化,可以直接使用。
VS2019 自带的工具 dumpbin.exe 可以查看编译后的 动态链接库对应的 函数名。
打开命令行,输入命令 dumpbin -exports CPPDLL.dll
结果截图:
所以 addFunc 不能直接使用,只能用被 name Mangling 后的名字 ,这里 addFunc 编译后的名字是 ?addFunc@@YAHHH@Z
示例程序代码:
#include <iostream>
#include <windows.h>
// 加、减、乘 都是 int 类型
typedef int(*lpFunc)(int a, int b); //后边为参数,前面为返回值
// 除法 是 double 类型
typedef double(*lpFuncD)(double a, double b); //后边为参数,前面为返回值
int main()
{
std::cout << "Hello World!\n";
HMODULE hModule;
hModule = LoadLibrary(L"CPPDLL.dll"); //调用DLL
lpFunc lpfunc = NULL;
// GetProcAddress为获取该函数的地址
// "?addFunc@@YAHHH@Z" 这个就是 C++ Name Mangling后的 addFunc 的函数名
lpfunc = (lpFunc)GetProcAddress(hModule, "?addFunc@@YAHHH@Z");
std::cout << lpfunc(1, 2) << std::endl;
/* 使用 C extern 和 def 文件定义的动态链接库,函数名不会发生变化 */
lpfunc = (lpFunc)GetProcAddress(hModule, "subFunc");
std::cout << lpfunc(3, 4) << std::endl;
lpfunc = (lpFunc)GetProcAddress(hModule, "mulFunc");
std::cout << lpfunc(5, 6) << std::endl;
lpFuncD lpfuncd = NULL;
lpfuncd = (lpFuncD)GetProcAddress(hModule, "divFunc");
std::cout << lpfuncd(7, 8) << std::endl;
//释放
FreeLibrary(hModule);
}
运行结果:
方法 5:使用 lib 文件 和 dll 文件
- 把CPPDLL.dll文件放到 debug 目录下,
- 然后在项目中引入CPPDLL.lib文件。 链接器->输入->附加依赖项->编辑
示例代码:
#include <iostream>
// addFunc 是使用 C++ 方式声明的,
_declspec(dllimport) int addFunc(int a, int b);
//subFunc 是 使用 extern "C" 声明的
extern "C" _declspec(dllimport) int subFunc(int a, int b);
// mulFunc 和 divFunc 是 使用 def 声明的
_declspec(dllimport) int mulFunc(int a, int b);
_declspec(dllimport) double divFunc(double a, double b);
int main()
{
std::cout << "Hello World!\n";
std::cout << addFunc(1, 2) << std::endl;
std::cout << subFunc(3, 4) << std::endl;
std::cout << mulFunc(5, 6) << std::endl;
std::cout << divFunc(7, 8) << std::endl;
return 0;
}
运行结果:
还可以结合 第一种方法,使用 #pragma comment (lib,"./CPPDLL.lib") //添加 lib 文件
这样就不用 手动设置 添加 lib 文件了
#include <iostream>
#pragma comment (lib,"./CPPDLL.lib")
// addFunc 是使用 C++ 方式声明的,
_declspec(dllimport) int addFunc(int a, int b); // 声明 addFunc 函数
//subFunc 是 使用 extern "C" 声明的
extern "C" _declspec(dllimport) int subFunc(int a, int b); // 声明 subFunc 函数
// mulFunc 和 divFunc 是 使用 def 声明的
_declspec(dllimport) int mulFunc(int a, int b); // 声明 mulFunc 函数
_declspec(dllimport) double divFunc(double a, double b); // 声明 divFunc 函数
int main()
{
std::cout << "Hello World!\n";
std::cout << addFunc(1, 2) << std::endl;
std::cout << subFunc(3, 4) << std::endl;
std::cout << mulFunc(5, 6) << std::endl;
std::cout << divFunc(7, 8) << std::endl;
return 0;
}