VS2019环境下动态链接库DLL的创建与调用(动态调用隐式链接)
欢迎阅读
你好! 这是我第一次写博文,有不足之处烦请指出。
声明
本文内容由作者查阅多方资料,亲自实验后总结得出!严禁任何形式的抄袭!请尊重作者!
一、实验环境
VS2019、Win10
二、创建动态链接库(DLL)
首先,我们需要知道动态链接库(以下简称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:
单击
或者
按下’F5’
之后编译器会进行编译,成功之后会显示一个无法启动的错误,如下图:
不必担心,这是正常的现象,因为DLL不是可执行文件.exe,所以无法被启动,单击‘确定’即可。
如果出现的是其他错误,还需根据“错误列表”自行改正错误!
至此,DLL的创建全部完成!
此时在TestDLL的工程目录下的Debug文件夹中会出现如下图所示的5个文件:
其中“TestDLL.dll”和“TestDLL.lib”是我们等会儿会用到的文件。
三、调用动态链接库(DLL)
通过上面的步骤,我们现在已经创建好了可被调用的DLL了,接下来需要创建一个调用TestDLL的C++工程项目
步骤<1>:新建一个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";
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
修改
//修改后的代码
//
//
// TestDLLCreated.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "TestDLL.h"
int main()
{
SayHello();
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
分析:在“TestDLLCreated.cpp”源文件中先include头文件“TestDLL.h”(去掉#include 是因为它在“TestDLL.h”已经被包含了),然后在main()函数中调用被导入的SayHello()函数。
至此,调用代码编写完成!
步骤<3>:编译代码
单击
或者
按下’F5’
编译成功之后的结果如下:
成功调用,说明所有工作都已正确完成!
四、总结
1、上述教程只适用于调试模式下,若想直接启动TestDLLCreated.exe应用程序,还需将“TestDLL.dll”和“TestDLL.lib”文件复制到与TestDLLCreated.exe同一目录下才可以运行!
2、希望可以帮到大家。