VS(visual studio) C++ 封装dll,以及其隐式调用与显式调用(静态\动态)
DLL介绍
DLL (动态链接库,Dynamic Link Library)是一种可执行文件,它包含可以在其他程序中调用的函数和数据。他是Windows操作系统中的一个重要概念,用于代码共享和模块化。
特点
- 代码共享 :多个程序可以同时使用同一个DLL文件,而 不需要将其代码编译到每个程序中 。这样可以节省磁盘空间和内存,并且可以简化程序的更新和维护。
-
运行时链接
:与静态链接库(
.lib
文件)不同,DLL不是在编译时链接到程序中的,而是在程序运行时链接。这意味着,如果更新了DLL,使用该DLL的程序可以在不重新编译的情况下直接使用新版本。 - 多语言支持 :DLL可以由不同的语言编写,例如C,C++,Delphi等,只要它们遵循一定的调用约定。
- 可拓展性 :应用程序可以通过加载和卸载DLL来动态地增加或减少功能。
- 资源共享 :DLL在内存中只有一个实例,所有使用它的应用程序都共享这个实例,从而节约了资源。
生成DLL
新建dll项目
新建项目-选择“win32控制台应用程序”
接着在弹出框中选择
dll
和空项目
完成后得到空项目的目录结构,创建
DLL1.h
和
DLL1.cpp
两个文件
书写代码
-
在
DLL1.cpp
中实现两个数求和与求差的接口:
int sum(int a, int b){
return a + b;
}
int sub(int a, int b){
return a - b;
}
-
在
DLL1.h
中声明函数:
int sum(int a, int b);
int sub(int a, int b);
-
为了能在dll中使用,还需要给函数加上前缀:
extern "C" __declspec(dllexport)
-
其中
_declspec(dllexport)
的意思是指定需要导出到dll的目标(用于生成dll) -
extern "C"
表示将C语言程序导出为DLL
-
extern "C" __declspec(dllexport) int sum(int a, int b);
extern "C" __declspec(dllexport) int sub(int a, int b);
也可以使用宏定义,使代码更具可读性
#define SumAndSub_API __declspec(dllexport)
extern "C" SumAndSub_API int sum(int a, int b);
extern "C" SumAndSub_API int sub(int a, int b);
生成DLL
在
.h
和
.cpp
中添加代码之后,右击项目选择“生成”
生成成功后,在项目
Debug
文件夹下即可找到生成的dll文件
.h
所在目录也需要记录一下
到这DLL的封装算是完成了
调用DLL
隐式调用
首先需要重新创建一个空项目来调用测试:
创建完成之后,还需引入三个文件即前面生成的
DLL1.dll
和
DLL1.lib
以及项目
DLL1.h
文件
其中
DLL1.dll
需要放在当前项目的
Debug
目录下,其他两个在属性中配置路径即可(
DLL1.lib
还需添加依赖项)
右击项目-选择属性
选择
VC++目录
其中“包含目录” 添加
.h
文件所在文件夹
“库目录”添加
.lib
所在目录
添加完成后如图:
然后在链接器-输入选项中添加依赖项
完成后应用属性保存,然后将DLL文件复制到当前项目的
Debug
目录下
下面新建一个
test.cpp
来测试下是否能够成功调用到DLL
#include "iostream"
#include "DLL1.h"
using namespace std;
int main(){
cout << sum(2, 5) << endl;
cout << sub(5, 2) << endl;
system("pause");
return 0;
}
成功调用到DLL
显式调用
显式调用中又包含 静态调用 与 动态调用 。
静态显式调用
-
静态调用:
.lib
文件包含了函数代码本身,在编译时直接将代码加入程序当中,称为 静态链接库(static link library) 。静态调用使用静态链接库,链接器从静态链接库LIB获取所有被引用函数,并将库同代码一起放到可执行文件中。
先创建一个新的空项目,创建完成后添加一个
.cpp
源文件并写入简单的主函数
int main(){
}
右击项目选择-生成(生成
Debug
目录)
把
DLL1.dll
放到当前项目的
Debug
目录下
创建
.cpp
源文件通过以下代码进行静态调用
#include "iostream"
using namespace std;
#pragma comment(lib, "D:\\Code\\C++\\dll\\DLL1\\Debug\\DLL1.lib")
// dll中封装的函数
extern "C" __declspec(dllimport) int sum(int, int);
extern "C" __declspec(dllimport) int sub(int, int);
int main(){
cout << sum(2, 5) << endl;
cout << sub(5, 2) << endl;
system("pause");
return 0;
}
其中
#pragma comment(lib, "D:\\Code\\C++\\dll\\DLL1\\Debug\\DLL1.lib")
表示链接
DLL1.lib
这个库,与在项目属性中的“VC++目录”中的“库目录”添加目录以及链接器-输入添加依赖性操作是等价的(一个显式一个隐式的区别)。
动态显式调用
-
动态调用:
.lib
文件包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为 动态链接库(dynamic link library) 。动态调用使用动态链接库,可执行模块(.dll文件或.exe文件)本身不包含它调用的DLL函数的代码,仅包含在运行时定位DLL函数的代码所需的信息,在程序运行时能够找到并链接到正确的DLL文件和函数。(这些信息通常包括函数名、参数类型等,足以让操作系统在运行时解析并调用正确的函数。)
同样创建项目后先生成
Debug
目录
生成之后将
DLL1.dll
放入Debug目录中
通过如下方式进行动态调用
-
首先通过
LoadLibrary()
函数来载入指定的dll文件,加载到程序的内存中(DLL没有自己的内存) -
GetProcAddress()
函数检索指定dll文件输出库函数地址,通过函数指针typedef int(*func)(int a, int b);
来装载函数并使用。 -
FreeLibrary()
释放dll所占的空间。
#include "iostream"
#include "windows.h"
using namespace std;
typedef int(*func)(int a, int b);
int main(){
// 动态加载dll
HMODULE hModule = LoadLibrary("DLL1.dll");
if (!hModule){
cout << "Error!" << endl;
}
// 装载函数
func sum = func(GetProcAddress(hModule, "sum"));
func sub = func(GetProcAddress(hModule, "sub"));
if (sum != NULL){
cout << sum(5, 2) << endl;
}
if (sub != NULL){
cout << sub(5, 2) << endl;
}
// 释放
FreeLibrary(hModule);
system("pause");
return 0;
}
加载dll的LoadLibrary()函数同样可以使用绝对路径,就无需将dll文件放到Debug目录下了
// 动态加载dll
HMODULE hModule = LoadLibrary("D:\\Code\\C++\\dll\\DLL1\\Debug\\DLL1.dll");
注意:动态调用方式通常是只有
.dll
文件,而缺少
.h
和
.lib
文件时使用,
当三个文件都齐全时,应采用更加简单方便的隐式调用
。
以上就是电脑114游戏给大家带来的关于VS(visual studio) C++ 封装dll,以及其隐式调用与显式调用(静态\动态)全部内容,更多攻略请关注电脑114游戏。
电脑114游戏-好玩游戏攻略集合版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!