VS2019中C++动态链接库(DLL)的创建与调用

VS2019中C++动态链接库(DLL)的创建与调用

本教程转载自:CSDN博主「Aishen1024」的原创文章 VS2019环境下C++动态链接库(DLL)的创建与调用

在以上教程基础上,添加了更多进阶技巧及可能会遇到的一些问题和解决方案。

一、创建DLL

1、创建新项目–>动态链接库(DLL)

在这里插入图片描述

2、配置新项目

在这里插入图片描述

3、初始化界面

创建工程之后的初始化界面,其中的代码是自动生成的,我们不需要去修改!
在这里插入图片描述

4、新建文件

接下来创建我们自己的DLL:
(1)首先新创建头文件“TestDLL.h”,它的作用是用来声明需要导出的函数接口。
在这里插入图片描述
(2)然后新创建源文件“TestDLL.cpp”,它的作用是用来实现被声明的函数。
在这里插入图片描述
此时工程目录结构如下图:
在这里插入图片描述

5、代码编写

1)首先我们要在‘TestDLL.h’中编写如下代码:

#pragma once
#include <iostream>
 
extern "C" __declspec(dllexport) void SayHello();

上面代码的功能是声明一个可被调用的函数“SayHello()”,它的返回类型是void。

现在分析一下extern “C” __declspec(dllexport) void SayHello();这一句代码,其中extern "C"的作用是告诉编译器将被它修饰的代码按C语言的方式进行编译,这么做的意义在此不做讨论,感兴趣的话可自行查询。
然后分析__declspec(dllexport),此修饰符告诉编译器和链接器被它修饰的函数或变量需要从DLL导出,以供其他应用程序使用;与其相对的还有一句代码是__declspec(dllimport),此修饰符的作用是告诉编译器和链接器被它修饰的函数或变量需要从DLL导入,它在后面也会被用到。
最后是函数void SayHello(),它就是需要被其他程序调用的函数。

效果图如下:
在这里插入图片描述
(2)然后我们需要在‘TestDLL.cpp’中实现在‘TestDLL.h’中被声明的SayHello()函数,代码如下:

#include "pch.h"
#include "TestDLL.h"
 
void SayHello()
{
    std::cout << "Hello!你成功了!" << std::endl;
}

效果图如下:
在这里插入图片描述
至此,DLL的代码编写完成。

6、编译

编译器会进行编译,成功之后会显示一个无法启动的错误,如下图:
在这里插入图片描述
不必担心,这是正常的现象,因为DLL不是可执行文件.exe,所以无法被启动,单击‘确定’即可。
如果出现的是其他错误,还需根据“错误列表”自行改正错误!

至此,DLL的创建全部完成!

此时在TestDLL的工程目录下的Debug文件夹中会出现如下图所示的5个文件:
在这里插入图片描述
其中“TestDLL.dll”和“TestDLL.lib”是我们等会儿会用到的文件。

二、调用DLL

1、新建一个C++工程项目

通过上面的步骤,我们现在已经创建好了可被调用的DLL了,接下来需要创建一个调用TestDLL的C++工程项目。
此处创建C++工程项目的目的是为了测试刚刚写好的TestDLL库,所以和创建普通的C++工程项目一样没有什么区别,所以此处不再给出详细的创建过程。
下图显示的是我已经创建好了的名为“TestDLLCreated”的C++工程项目:
在这里插入图片描述

2、准备工作

这一步需要做以下几件事:

  1. 将TestDLL的工程目录下的Debug文件夹中的“TestDLL.dll”和“TestDLL.lib”文件复制到“TestDLLCreated”工程目录下的TestDLLCreated文件夹中。

注意:每个人的工程目录的路径可能不太一样

在这里插入图片描述
复制到
在这里插入图片描述
2.将TestDLL的工程目录下的TestDLL文件夹中的“TestDLL.h”头文件复制到“TestDLLCreated”工程目录下的TestDLLCreated文件夹中

注意:每个人的工程目录的路径可能不太一样


在这里插入图片描述
复制到
在这里插入图片描述
3.将刚刚添加到“TestDLLCreated”工程目录下的TestDLLCreated文件夹中的“TestDLL.h”头文件导入到VS中的解决方案资源管理器中。

选择“添加”–>“现有项”
在这里插入图片描述
选择“TestDLL.h”之后点击添加按钮:
在这里插入图片描述
添加完成之后:
在这里插入图片描述

3、编写调用代码

1.首先修改“TestDLL.h”头文件中的代码:

//原来的代码
#pragma once
#include <iostream>
 
extern "C" __declspec(dllexport) void SayHello();

修改


//修改后的代码
#pragma once
#pragma comment(lib,"TestDLL.lib")
#include <iostream>
 
extern "C" __declspec(dllimport) void SayHello();

在这里分析一下为什么要这样修改,首先是添加了一行代码:#pragma comment(lib,“TestDLL.lib”),它的作用是将“TestDLL.dll”链接到TestDLLCreated工程项目中;
然后将代码extern “C” __declspec(dllexport) void SayHello();修改为extern “C” __declspec(dllimport) void SayHello();,作用是告诉编译器和链接器被__declspec(dllimport)修饰的函数或变量需要从DLL导入,前面也有过介绍。

2.然后,修改TestDLLCreated.cpp源文件中的代码

//原来的代码
//
//
// TestDLLCreated.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include <iostream>
 
int main()
{
    std::cout << "Hello World!\n";
}

修改


//修改后的代码
//
//
// TestDLLCreated.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include "TestDLL.h"
 
int main()
{
	SayHello();
}

4、编译

编译成功之后的结果如下:
在这里插入图片描述
成功调用,说明所有工作都已正确完成!

三、进阶技巧

提供一些进阶技巧,用于减少“二、调用DLL-》2、准备工作”中的手动操作。

1、链接lib文件,而不需要手动复制

(1)在需要调用DLL的工程属性中,修改“链接器-》输入-》附加依赖项”。添加生成DLL的lib文件。
在这里插入图片描述
(2)在需要调用DLL的工程属性中,修改“链接器-》常规-》附加库目录”。添加生成DLL的lib文件所在的文件夹。
在这里插入图片描述

2、编译后自动复制dll文件,而不需要手动复制

(1)在创建DLL的工程属性中,修改“生成事件-》生成后时间-》命令行”。添加copy命令,将生成的DLL在编译后自动复制到需要调用DLL的工程中。
命令行示例如下(地址根据自己的情况修改):

copy D:\4测试代码\DLL\1CreateDll\TestDll\x64\Debug\TestDll.dll D:\4测试代码\DLL\2UseDll\UseDll\UseDll\TestDll.dll

在这里插入图片描述
(2)编译后,可以在输出中看到复制dll成功,并且在调用DLL的工程下,可以看到复制过来的最新的dll。
在这里插入图片描述
在这里插入图片描述

3、修改创建dll工程的.h文件,使得创建dll的工程和调用dll的工程可以使用同一个.h文件,而不需要复制

(1)在创建DLL的工程属性中,修改“C\C+±》预处理器-》预处理器定义”。新增一个宏定义量,如IS_EXPORTS。
在这里插入图片描述

(2)创建dll工程的.h中的代码

//原来的代码
#pragma once
#include <iostream>
 
extern "C" __declspec(dllexport) void SayHello();

修改

#pragma once
#include <iostream>

#ifdef IS_EXPORTS
	__declspec(dllexport) void SayHello();
#else
	 __declspec(dllimport) void SayHello();
#endif

修改后,在创建DLL的工程中,会定义__declspec(dllexport) void SayHello(),即SayHello()函数由DLL输出;而在调用DLL的其它工程中,会定义__declspec(dllimport) void SayHello(),即SayHello()函数由DLL输入。

(2)在需要调用DLL的工程属性中,修改“C/C+±》常规-》附加包含目录”。添加创建DLL的.h文件所在的文件夹。
在这里插入图片描述

4、调试创建DLL的工程

在创建DLL的工程属性中,修改“调试-》命令”。选择调用DLL的工程的.exe,即可以调试创建DLL的工程。
在这里插入图片描述

5、可能会出现的问题及解决方案

在创建DLL的工程时,可能会出现以下错误,:
错误 C4430 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
在这里插入图片描述
解决方案:
始终把“pch.h”放在.cpp文件的最上方
在这里插入图片描述

  • 4
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态链接库是一种可重定位的二进制文件,它包含了一些可供其他程序调用的函数或数据。在 Windows 平台上,动态链接库采用 .dll 后缀名,而在 Linux 平台上则采用 .so 后缀名。在本文,我们将介绍如何使用 MFC 调用 C 语言编写的动态链接库。 # 创建动态链接库 在 Windows 平台上,可以使用 Visual Studio 创建动态链接库。下面是一个简单的示例: ```c // mydll.h #ifndef MYDLL_H #define MYDLL_H #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) int add(int a, int b); #ifdef __cplusplus } #endif #endif // MYDLL_H // mydll.c #include "mydll.h" int add(int a, int b) { return a + b; } ``` 这个动态链接库包含一个 add 函数,可以对两个整数求和。 # 调用动态链接库 在 MFC 项目调用动态链接库,需要进行以下几个步骤: 1. 定义一个函数指针类型,指向动态链接库的函数。 ```c++ typedef int (*AddFunc)(int, int); ``` 2. 加载动态链接库。 ```c++ HINSTANCE hinstLib = LoadLibrary(TEXT("mydll.dll")); if (hinstLib == NULL) { AfxMessageBox(TEXT("Failed to load library.")); return; } ``` 3. 获取动态链接库的函数地址。 ```c++ AddFunc addFunc = (AddFunc)GetProcAddress(hinstLib, "add"); if (addFunc == NULL) { AfxMessageBox(TEXT("Failed to get function address.")); FreeLibrary(hinstLib); return; } ``` 4. 调用动态链接库的函数。 ```c++ int result = addFunc(1, 2); CString str; str.Format(TEXT("1 + 2 = %d"), result); AfxMessageBox(str); ``` 5. 卸载动态链接库。 ```c++ FreeLibrary(hinstLib); ``` 完整的 MFC 代码示例: ```c++ typedef int (*AddFunc)(int, int); void CMyDlg::OnButton1() { HINSTANCE hinstLib = LoadLibrary(TEXT("mydll.dll")); if (hinstLib == NULL) { AfxMessageBox(TEXT("Failed to load library.")); return; } AddFunc addFunc = (AddFunc)GetProcAddress(hinstLib, "add"); if (addFunc == NULL) { AfxMessageBox(TEXT("Failed to get function address.")); FreeLibrary(hinstLib); return; } int result = addFunc(1, 2); CString str; str.Format(TEXT("1 + 2 = %d"), result); AfxMessageBox(str); FreeLibrary(hinstLib); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值