【08】C++实战篇——C++ 生成动态库.dll 及 C++调用DLL,及实际项目中的使用技巧

文章目录

  • 一、创建动态库dll (方法一)
    • [1 生成C++ 动态库dll](#1 生成C++ 动态库dll)
      • [1.1 创建项目MyDLL](#1.1 创建项目MyDLL)
      • [1.2 编写.h 和 .cpp文件](#1.2 编写.h 和 .cpp文件)
      • [1.3 设置 及 生成 DLL](#1.3 设置 及 生成 DLL)
    • [2 调用 C++ 动态库dll](#2 调用 C++ 动态库dll)
      • [2.1 创建C++ 空项目DLLtest](#2.1 创建C++ 空项目DLLtest)
      • [2.2 动态库配置 及代码调用测试](#2.2 动态库配置 及代码调用测试)
    • [3 实际项目中的使用技巧](#3 实际项目中的使用技巧)
      • [3.1 设置dll输出路径](#3.1 设置dll输出路径)
      • [3.2 设置头文件引入路径](#3.2 设置头文件引入路径)
      • [3.3 改进后 测试](#3.3 改进后 测试)
    • [4 __cplusplus 解释](#4 __cplusplus 解释)
    • [5 完整代码.h文件、.cpp 文件](#5 完整代码.h文件、.cpp 文件)
    • [6 完整项目文件下载](#6 完整项目文件下载)

创建动态库dll项目有两种方法;

  • 1.VS创建 C++ 空项目 ,然后在项目属性中将项目 配置类型 改为 动态库(.dll),规范性要求不高,且创建方式熟悉。这种方法也可以用,但有时这种方法生成的dll在项目调用中, 会出现各种奇怪的错误。 故,此法 多用于新手测试,正式项目慎用。
  • 2.VS创建 动态链接库(DLL) 项目, 更安全、正规,代码要求更规范。

一、创建动态库dll (方法一)

1 生成C++ 动态库dll

为了验证效果,使用三种方法导出函数:

  • //导出函数
  • //导出类
  • //以C方式导出函数
cpp 复制代码
创建动态库d11:
	1.VS创建动态链接库(DLL) MyDLL:
	    编写.h和.cpp文件
		在.h文件中宏定义导出图数
   2.生成dll文件:
	    右键项目-->属性-->配置类型-->动态库( .dll)
	    以Debug x64 生成解决方案

1.1 创建项目MyDLL

1.VS创建C++ 空项目MyDLL:

1.2 编写.h 和 .cpp文件

添加 mathTest.hmathTest.cpp文件

mathTest.h 文件

cpp 复制代码
#pragma once
#ifndef MATHTEST_H
#define MATHTEST_H

//宏定义导出:
#ifndef MATHTEST_ //如果没有定义 MATHTEST_,就定义MATHTEST_API __declspec(dllexport)
#define MATHTEST_API __declspec(dllexport) //导出
#else
#define MATHTEST_API __declspec(dllimport) //导入
#endif


//导出函数
MATHTEST_API int add(int a, int b);//加法
MATHTEST_API int subtract(int a, int b);//减法


//导出类
class MATHTEST_API mathTest
{

public:

	int multiply(int a, int b);//乘法
	int divide(int a, int b);//除法
};


//以C方式导出函数
//extern "C",告诉编译器这里是C语言代码

//为了使自己建的库可以在 C/C++ 通用调用,使用 __cplusplus ,
//当C++调用代码时,__cplusplus 值为1,声明函数外面就加了一层"extern "C" {}";
//当C 调用代码时,__cplusplus 值为0,就相当于没有"extern "C" {}";

#ifdef __cplusplus 
extern "C"
{
#endif

	MATHTEST_API int Cadd(int a, int b);//加法
	MATHTEST_API int Csubtract(int a, int b);//减法
#ifdef __cplusplus
}
#endif


#endif

mathTest.cpp文件

cpp 复制代码
#include "mathTest.h"

/*创建动态库d11:
	1.VS创建C++ 空项目MyDLL:
	    编写.h和.cpp文件
		在.h文件中宏定义导出图数
	2.生成dll文件:
	    右键项目-->属性-->配置类型-->动态库( .dll)
	    以Debug x64 生成解决方案
*/

//导出函数
int add(int a, int b)//加法
{
	return a + b;
}
int subtract(int a, int b)//减法
{
	return a - b;
}

//导出类
int mathTest::multiply(int a, int b)//乘法
{
	return a * b;
}

int mathTest::divide(int a, int b)//除法
{
	return a / b;
}



//以C方式导出函数
int Cadd(int a, int b)//加法
{
	return a + b;
}

int Csubtract(int a, int b)//减法
{
	return a - b;
}

1.3 设置 及 生成 DLL

右键项目-->属性-->配置类型-->动态库( .dll)

右键项目-->生成 (如修改后,可以点重新生成)

查看 生成的DLL文件

查看DLL

注意是.E:\Test\MyDLL\x64\Debug,在工程同级目录下\x64\Debug下面

而不是 E:\Test\MyDLL\MyDLL\x64\Debug,而不是在.h同级目录的\x64\Debug下面(刚开始就在这里找,发现MyDLL.dll.recipe多了一个.recipe,迷糊了半天

2 调用 C++ 动态库dll

方法:

cpp 复制代码
创建C++ 空项目DLLtest

使用动态库d11:
   隐式调用:
	 1.把.lib(MyDLL.lib)、.dll(MyDLL.d11)、.h(mathTest.h)文件放到工程目录下(DLLtest项目的.cpp同目录下)
	 2.项目右键-- > 属性-->配置属性-->链接器-->输入->附加依项-- > 添加MyDLL.lib
	 3.#include mathTest.h
	      
     4.代码调用

2.1 创建C++ 空项目DLLtest

这里测试代码有两种建里新项目的方法:

  • 1可以直接在 "MyDLL"解决方案下 建创建C++ 空项目DLLtest;( 实际项目中dll项目和用户项目建立在同一个解决方案下,这样更方便代码修改与管理,在调试时 主项目代码还可以直接调试访问dll中的源代码,这样就更方便dll代码的调试优化等操作。)
  • 2 也单独建立一个项目方案;

这里为了方便,直接原来的解决方案上新增测试项目这样做的好处是,如果测试之后dll代码有问题或功能达不到预期,可以方便随时修改dll的源代码。

右键 解决方案"MyDLL" ->添加 ->新建项目;创建C++ 空项目DLLtest

可以看到,解决方案下有两个项目,"DLLtest"和"MyDLL"

在DLLtest项目下添加,main.cpp文件

2.2 动态库配置 及代码调用测试

使用动态库d11:

隐式调用:

cpp使用动态库d11: 复制代码
   隐式调用:
	 1.把.lib(MyDLL.lib)、.dll(MyDLL.dll)、.h(mathTest.h)文件放到工程目录下(DLLtest项目的.cpp同目录下)
	 2.项目右键-- > 属性-->配置属性-->链接器-->输入->附加依项-- > 添加MyDLL.lib
	 3.#include mathTest.h
     
     4.代码调用

在我们的dll文件中分别设置了 导出函数、导出类成员函数、以C方式导出的函数,现在这三种函数都在main文件中调用测试。

完整代码

cpp 复制代码
#include<iostream>
#include"mathTest.h"
using namespace std;

/*
VS创建C++ 空项目DLLtest

使用动态库d11:
   隐式调用:
	 1.把.lib(MyDLL.lib)、.d11(MyDLL.d11)、.h(mathTest.h)文件放到工程目录下(DLLtest项目的.cpp同目录下)
	 2.项目右键-- > 属性-->配置属性-->链接器-->输入->附加依项-- > 添加MyDLL.1b
	 3.#include mathTest.h

	  4.代码调用
*/


int main()
{


	//调用dll 导出函数
	int sum = add(10, 5);
	int sub = subtract(10, 5);

	//调用dll 导出类成员函数
	mathTest mathT; //实例化对象
	int mul = mathT.multiply(10, 5);
	int div = mathT.divide(10, 5);


	//调用dll 以C方式导出的函数
	int Csum = Cadd(10, 5);
	int Csub = Csubtract(10, 5);

	cout << "我的动态库dll调用: "<< endl;
	cout << "add(10,5) = " << sum << endl
		 << "subtract(10,5) = " << sub << endl
		 << "multiply(10,5) = " << mul << endl
		 << "divide(10,5) = " << div << endl
	     << "Cadd(10,5) = " << Csum << endl
		 << "Csubtract(10,5) = " << Csub << endl;

	return 0;
}

运行测试,报错。是因为 当前启动项为"MyDLL",需要将启动项设为 "DLLtest"。

右键 "DLLtest",选择"设为启动项"


导出函数、导出类成员函数、以C方式导出的函数 ,现在这三种函数都用结果都输出了,说明这三种dll导出函数方式都有,但我最常用的是 以C方式导出的函 ,这中通用个,避免出错。

3 实际项目中的使用技巧

自动路径(.dll、.lib、.h复制到 测试项目的.cpp目录下,太麻烦)

3.1 设置dll输出路径

直接将dll生成文件,的生路径设为 "DLLtest"项目下的.cpp路径;

打开项目,观察路径位置关系

为了是的路径通用,这里使用相对路径 ../DLLtest/,并且将 MyDLL设为启动项,方便后面dll重新生成

重新生成dll,可见新的dll文件已经 生成在DLLtest项目下面了

3.2 设置头文件引入路径

将DLLtest设为启动项;

设置DLLtest项目的 附加包含目录为 .../MyDLL/这样DLLtest项目就可以访问 mathTest.h 文件了。

3.3 改进后 测试

注意:既然新的dll生成路径已经更改到 "DLLtest"项目下的.cpp路径,那么第一次在 MyDLL\x64\Debug\路径下生成的生成的dll最好删掉,

不然两个路径同时存在dll,调用时会产生混淆,当两个路径下的dll代码源文件完全一样时,似乎并没有影响。一旦新的dll代码修改了,这时两个路径下dll内容不一致,调用运行时就会出错。

所以下面的4文件删掉。

4 __cplusplus 解释

为了使自己建的 C/C++ 库可 都可以通用

使用 __cplusplus

  • 当C++代码时,__cplusplus 值为1;
  • 当C 代码时,__cplusplus 值为0;
c 复制代码
#ifdef __cplusplus 
.
.
.
#endif

下面是完整的.h文件

c 复制代码
//#pragma once
#ifndef MATHTEST_H
#define MATHTEST_H

//宏定义导出:
#ifndef MATHTEST_ //如果没有定义 MATHTEST_,就定义MATHTEST_API __declspec(dllexport)
#define MATHTEST_API __declspec(dllexport) //导出
#else
#define MATHTEST_API __declspec(dllimport) //导入
#endif


//动态链接MATHTEST_API库


//以C语言的方式导出函数
//extern "C",告诉编译器这里是C语言代码

#ifdef __cplusplus 
extern "C"
{
#endif

	MATHTEST_API int Cadd(int a, int b);     //加法
	MATHTEST_API int Csubtract(int a, int b);//减法
	MATHTEST_API int Cmultiply(int a, int b); //乘法
	MATHTEST_API int Cdivide(int a, int b);   //除法

#ifdef __cplusplus
}
#endif

#endif

当C++ 代码时,__cplusplus 值为1,那么源代码对应部分 等价于

c 复制代码
extern "C"
{
	MATHTEST_API int Cadd(int a, int b);     //加法
	MATHTEST_API int Csubtract(int a, int b);//减法
	MATHTEST_API int Cmultiply(int a, int b); //乘法
	MATHTEST_API int Cdivide(int a, int b);   //除法
}
#endif

当C 代码时,__cplusplus 值为0,那么源代码 对应部分 等价于;

#ifdef __cplusplus ...#endif 部分是没有执行的

c 复制代码
	MATHTEST_API int Cadd(int a, int b);     //加法
	MATHTEST_API int Csubtract(int a, int b);//减法
	MATHTEST_API int Cmultiply(int a, int b); //乘法
	MATHTEST_API int Cdivide(int a, int b);   //除法

5 完整代码.h文件、.cpp 文件

为了统一规范,同时使用"以C语言的方式导出函数"

mathTest.h文件

c 复制代码
#pragma once
#ifndef MATHTEST_H
#define MATHTEST_H

//宏定义导出:
#ifndef MATHTEST_ //如果没有定义 MATHTEST_,就定义MATHTEST_API __declspec(dllexport)
#define MATHTEST_API __declspec(dllexport) //导出
#else
#define MATHTEST_API __declspec(dllimport) //导入
#endif


//以C方式导出函数
//extern "C",告诉编译器这里是C语言代码

//为了使自己建的库可以在 C/C++ 通用调用,使用 __cplusplus ,
//当C++调用代码时,__cplusplus 值为1,声明函数外面就加了一层"extern "C" {}";
//当C 调用代码时,__cplusplus 值为0,就相当于没有"extern "C" {}";

#ifdef __cplusplus 
extern "C"
{
#endif

	MATHTEST_API int Cadd(int a, int b);     //加法
	MATHTEST_API int Csubtract(int a, int b);//减法
	MATHTEST_API int Cmultiply(int a, int b); //乘法
	MATHTEST_API int Cdivide(int a, int b);   //除法

#ifdef __cplusplus
}
#endif


#endif

mathTest.cpp文件

c 复制代码
#include<iostream>
#include"mathTest.h"
using namespace std;

/*
VS创建C++ 空项目DLLtest

使用动态库d11:
   隐式调用:
	 1.把.lib(MyDLL.lib)、.d11(MyDLL.d11)、.h(mathTest.h)文件放到工程目录下(DLLtest项目的.cpp同目录下)
	 2.项目右键-- > 属性-->配置属性-->链接器-->输入->附加依项-- > 添加MyDLL.1b
	 3.#include mathTest.h

	  4.代码调用
*/


int main()
{
	//调用以C方式导出的函数
	int Csum = Cadd(10, 5);
	int Csub = Csubtract(10, 5);
	int Cmul = Cmultiply(10, 5);
	int Cdiv = Cdivide(10, 5);


	cout << "我的动态库dll调用: " << endl;
	cout << "Cadd(10,5) = " << Csum << endl
		<< "Csubtract(10,5) = " << Csub << endl
		<< "Cmultiply(10,5) = " << Cmul << endl
		<< "Cdivide(10,5) = " << Cdiv << endl;

	return 0;
}

6 完整项目文件下载

完整项目工程文件,下载后可直接编译运行

代码下载:C++ 生成动态库.dll 及 C++调用DLL

相关推荐
朝朝又沐沐4 小时前
算法竞赛阶段二-数据结构(40)数据结构栈的STL
开发语言·数据结构·c++·算法
Antonio9155 小时前
【网络编程】WebSocket 实现简易Web多人聊天室
前端·网络·c++·websocket
清朝牢弟6 小时前
Ubuntu系统VScode实现opencv(c++)图像放缩与插值
c++·vscode·opencv·ubuntu·计算机视觉
呆瑜nuage6 小时前
list的使用和模拟
c++·list
tomato096 小时前
Codeforces Round 1040 (Div. 2)(补题)
c++
好好先森&7 小时前
C语言:模块化编程
c语言·c++·windows
爱学习的小邓同学7 小时前
c++ --- priority_queue的使用以及简单实现
c++
清朝牢弟9 小时前
Ubuntu系统VScode实现opencv(c++)视频的处理与保存
c++·人工智能·vscode·opencv·ubuntu