许久不写C++的已经快忘光了,最近刚好有用到,乘机整理一下C++中如何封装Dll以及如何调试,如何调用的知识。

关于动态链接库有什么好处,我就不多废口舌了,直接开干吧。

1、创建dll项目

2、创建头文件(.h)和源文件(.cpp)

2.1头文件编写

2.2源文件编写

3 调试dll


1、创建dll项目

打开VS(个人用的VS2019)→新建项目→在C++语言+库下选择动态连接库

meson怎么链接动态库 动态链接库如何调试_头文件

meson怎么链接动态库 动态链接库如何调试_dll_02

输入项目名称:CppDllDemo

点击【创建】

meson怎么链接动态库 动态链接库如何调试_头文件_03

2、创建头文件(.h)和源文件(.cpp)

在【解决方案资源管理器】中的【头文件】和【源文件】目录下,分别创建头文件:“CppDllDemo.h”和源文件:“CppDllDemo.cpp”。

meson怎么链接动态库 动态链接库如何调试_动态链接库_04

2.1、头文件编写

这个头文件是指要声明对外暴露的函数的头文件,dll项目中不对外暴露的组件可以新建其他头文件按照C++普通方式写就好了。

假设这次dll封装两个简单函数:两个double数的求和函数、打印“hello world”的函数。

这个主头文件 个人习惯是按照如下格式来写:

1、声明导出/导入宏

2、头文件标识 #ifndef HEAD_H #define HEAD_H
|
|    3、不得不包含的头文件
|
|    4、一些要用的结构体、类等
|
|    extern "C"
|    {
|    |    5、要导出的函数声明
|    |
|    |
|    |
|    }
|
┕结束头文件标识 #endif

 参考以上格式,查看如下代码(至少看起来不是很费劲了)

#pragma once
//定义导出、导入宏
#ifdef CPPDLLDEMO_EXPORTS
#define CPPDLLDEMO_API __declspec(dllexport)
#else
#define CPPDLLDEMO_API __declspec(dllimport)
#endif // CPPDLLDEMO_EXPORTS

//头文件标识
#ifndef CPPDLLDEMO_H
#define CPPDLLDEMO_H

/*----------------------{
包含一些不得不包含的头文件
}----------------------*/

/*----------------------{
这里写一些结构体、类等
}----------------------*/


#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus


	CPPDLLDEMO_API double Add(double a, double b);

	CPPDLLDEMO_API void SayHello();


#ifdef __cplusplus
}
#endif // __cplusplus


#endif // !CPPDLLDEMO_H

以上有几点要说明

1、关于“#ifdef CPPDLLDEMO_EXPORTS”

在创建好dll项目后,这个宏就已经被VS自动声明了,它的命名就是项目名全大写加“EXPORTS”。

你可以在子项目属性中的预编译中看到:

右键项目名,点击属性→【C/C++】→【预处理器】→【预处理器定义】

meson怎么链接动态库 动态链接库如何调试_dll_05

2、宏CPPDLLDEMO_API :__declspec(dllexport)和__declspec(dllimport)

在dll开发时,使用export,就是说带有这个的函数都是要输出供外部调用的

import是给外部的,其他程序导入这个dll时,带有宏标记的函数就会被导入。

3、extern "C" 

如果是C++(#ifdef __cplusplus),就强制按照C标准进行编译,因为C++编译会对函数名及进行修改,导致调用时的很多麻烦。

2.2、源文件编写

在头文件中只做了函数声明,函数的定义要在源文件中编写,在“CppDllDemo.cpp”中,完成函数的定义:

#include "pch.h"; //新版本的预编译头
#include "CppDllDemo.h"  //包含创建的头文件

#include <iostream>

using namespace std;

//函数定义

double Add(double a, double b)
{
	double c = a + b;
	return c;
}

void SayHello()
{
	cout << "Hello World!" << endl;
}

 以上,就编写完成了,选择合适的解决方案平台(Debug/Release?,x86/x64?)后生成项目即可。

如果有编译失败的,还请留言,我们一起研究研究。

编译成功后,在生成的目录下就能找到生成“DebugCppDll.dll”文件,当让还有一并生成的其他文件,诸如“xxx.lib”文件。

一般用动态方式加载dll的时候,直接拿“xxx.dll”文件去用就好了。

3 调试dll

dll项目不能像控制台程序一样的去运行,所以应该怎么调试呢,一般在dll项目的下,新建一个控制台程序(不嫌麻烦你也可以搞个mfc程序)来调试dll项目。

在VS的【解决方案资源管理器】中,dll项目名的上方,即“解决方案‘xxxxx’”处右键,点击【添加】→【新建项目】

meson怎么链接动态库 动态链接库如何调试_C++_06

选择C++控制台项目,取名“DebugCppDll”。

创建好后,在【解决方案资源管理器】中该项目名右键→【设为启动项目】。

再次右键 →【添加】→【引用】,在项目标签下选择刚才的dll项目

meson怎么链接动态库 动态链接库如何调试_C++_07

点击确定添加完成后,在“DebugCppDll”项目下新建源文件,写main函数入口(正常情况下VS已经帮你写好“hello world”的程序了)。在文件头添加dll中的“.h”文件,如下:

// DebugCppDll.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

#include <iostream>
#include "..\CppDllDemo\CppDllDemo.h"  //dll的头文件

using namespace std;

int main()
{
	double result = Add(4.5, 11.2); //调用 Add函数
	cout << "result = " << result << endl; //答应计算结果
	SayHello();  //调用SayHello函数
	cin.get();
}

运行可看到调用成功:

meson怎么链接动态库 动态链接库如何调试_dll_08

接着当我们需要调试时呢,转到dll项目中,比如在“CppDllDemo.cpp”中打上断点;

meson怎么链接动态库 动态链接库如何调试_动态链接库_09

这样再次启动“DebugCppDll”项目(是启动项,所以之间点VS上面的运行按钮就好),就会命中该断点,方便我们的调试。

meson怎么链接动态库 动态链接库如何调试_C++_10

---------------

尾巴:关于如何通过动态调用dll,下一篇文章进行详述