首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

VS(visual studio) C++ 封装dll,以及其隐式调用与显式调用(静态\动态)

编程知识
2024年09月20日 09:54

DLL介绍

DLL(动态链接库,Dynamic Link Library)是一种可执行文件,它包含可以在其他程序中调用的函数和数据。他是Windows操作系统中的一个重要概念,用于代码共享和模块化。

特点

  • 代码共享:多个程序可以同时使用同一个DLL文件,而不需要将其代码编译到每个程序中。这样可以节省磁盘空间和内存,并且可以简化程序的更新和维护。
  • 运行时链接:与静态链接库(.lib文件)不同,DLL不是在编译时链接到程序中的,而是在程序运行时链接。这意味着,如果更新了DLL,使用该DLL的程序可以在不重新编译的情况下直接使用新版本。
  • 多语言支持:DLL可以由不同的语言编写,例如C,C++,Delphi等,只要它们遵循一定的调用约定。
  • 可拓展性:应用程序可以通过加载和卸载DLL来动态地增加或减少功能。
  • 资源共享:DLL在内存中只有一个实例,所有使用它的应用程序都共享这个实例,从而节约了资源。

生成DLL

新建dll项目

新建项目-选择“win32控制台应用程序”

接着在弹出框中选择dll和空项目

完成后得到空项目的目录结构,创建DLL1.hDLL1.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.dllDLL1.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文件,而缺少.h.lib文件时使用,当三个文件都齐全时,应采用更加简单方便的隐式调用

From:https://www.cnblogs.com/1873cy/p/18420728
本文地址: http://www.shuzixingkong.net/article/2153
0评论
提交 加载更多评论
其他文章 .NET 7+Angular 4 轻量级新零售进销存系统
前言 给大家推荐一个专为新零售快消行业打造了一套高效的进销存管理系统。 系统不仅具备强大的库存管理功能,还集成了高性能的轻量级 POS 解决方案,确保页面加载速度极快,提供良好的用户体验。 项目介绍 Dorisoy.POS 是一款基于 .NET 7 和 Angular 4 开发的新零售快消进销存管理
.NET 7+Angular 4 轻量级新零售进销存系统 .NET 7+Angular 4 轻量级新零售进销存系统 .NET 7+Angular 4 轻量级新零售进销存系统
SaaS架构:流程架构分析
大家好,我是汤师爷~ 今天聊聊SaaS架构中的流程架构分析。 业务流程的概念 业务流程是企业为实现目标而制定的一套系统化的工作方法。它由一系列有序的业务活动组成,按照既定规则将资源(输入)转化为有价值的结果(输出)。这一过程需结合企业的具体情况和可用资源,旨在为客户创造价值,同时达成企业目标。 通过
SaaS架构:流程架构分析 SaaS架构:流程架构分析 SaaS架构:流程架构分析
基于语义增强的少样本检测,突破新类别偏见 | ICIP'24
Few-shot目标检测(FSOD)旨在在有限标注实例的情况下检测新颖对象,在近年取得了显著进展。然而,现有方法仍然存在偏见表示问题,特别是在极低标注情况下的新颖类别。在微调过程中,一种新颖类别可能会利用来自相似基础类别的知识来构建自己的特征分布,导致分类混淆和性能下降。为了解决这些挑战,论文提出了
基于语义增强的少样本检测,突破新类别偏见 | ICIP'24 基于语义增强的少样本检测,突破新类别偏见 | ICIP'24 基于语义增强的少样本检测,突破新类别偏见 | ICIP'24
Shiro-550—漏洞分析(CVE-2016-4437)
目录漏洞原理源码分析加密过程解密过程漏洞复现 漏洞原理 Shiro-550(CVE-2016-4437)反序列化漏洞 在调试cookie加密过程的时候发现开发者将AES-CBC用来加密的密钥硬编码了,并且所以导致我们拿到密钥后可以精心构造恶意payload替换cookie,然后让后台最后解密的时候进
Shiro-550—漏洞分析(CVE-2016-4437) Shiro-550—漏洞分析(CVE-2016-4437) Shiro-550—漏洞分析(CVE-2016-4437)
Advanced .Net Debugging 11:完结篇
一、介绍 这是我的《Advanced .Net Debugging》这个系列的第十一篇文章,也是这个系列的最后一篇了。我已经把原书的前八章内容全部写完了,本来打算继续写第九章和第十章的内容,后来我放弃逐章逐节的编写,选择了将两章的内容进行过滤后,合为一篇,只把重要的内容包含进来的做法。原因是,我看了
Advanced .Net Debugging 11:完结篇 Advanced .Net Debugging 11:完结篇 Advanced .Net Debugging 11:完结篇
痞子衡嵌入式:MCUBootUtility v6.3发布,支持获取与解析启动日志
-- 痞子衡维护的 NXP-MCUBootUtility 工具距离上一个大版本(v5.3.0)发布过去一年了,期间痞子衡也做过三个版本更新,但不足以单独介绍。这一次痞子衡为大家带来了全新重要版本v6.3.x,这次更新主要是想和大家特别聊聊 ROM 启动日志这个特性的支持。 一、v6.0 - v6.3
痞子衡嵌入式:MCUBootUtility v6.3发布,支持获取与解析启动日志 痞子衡嵌入式:MCUBootUtility v6.3发布,支持获取与解析启动日志
SimpleAISearch:C# + DuckDuckGo 实现简单的AI搜索
最近AI搜索很火爆,有Perplexity、秘塔AI、MindSearch、Perplexica、memfree、khoj等等。 在使用大语言模型的过程中,或许你也遇到了这种局限,就是无法获取网上最新的信息,导致回答的内容不是基于最新的信息,为了解决这个问题,可以通过LLM+搜索引擎的方式实现。 以
SimpleAISearch:C# + DuckDuckGo 实现简单的AI搜索 SimpleAISearch:C# + DuckDuckGo 实现简单的AI搜索 SimpleAISearch:C# + DuckDuckGo 实现简单的AI搜索
RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验
RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验
RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验 RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验 RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验