当前位置: 首页 > news >正文

【C++】Windows动态库【.DLL文件】制作方法总结

        如题,我们本篇介绍如何制作DLL,将代码类中的方法以接口的形式暴露出来给exe程序使用。会涉及类厂创建方法实例、声明DLL接口、.def文件的使用等。

目录

一、DLL介绍

二、C++制作DLL文件

2.1 DLL端

2.2 调用端

三、DLL导出类方法

四、COM技术制作DLL


一、DLL介绍

        我理解的DLL是windows下的可执行文件,也就是PE文件,学名动态链接库。一般调用DLL,也称加载DLL的是EXE文件。它是一种可重用的代码和数据的集合,可以由多个应用程序同时使用,与静态链接库不同,动态链接库在运行时加载到内存中,以供应用程序使用。

        一个exe程序可以带若干个dll,如下图:

         正常的windows程序基本都会带DLL,包括操作系统内核的DLL,所以很关键。

        DLL具有以下优点:

        可重用性:由于多个应用程序可以共享一个DLL,因此它们可以共享相同的代码和数据,从而提高了代码的可重用性。

        节省内存:由于DLL在运行时才加载到内存中,因此它们可以在不占用过多内存的情况下提供所需的功能。

        易于更新:当需要更新DLL时,只需替换现有的DLL文件即可,而无需重新编译使用该DLL的应用程序。

        动态链接:DLL在运行时才链接到应用程序中,因此它们可以在应用程序启动后动态加载,从而提高了应用程序的启动速度。

        稳定性:由于多个应用程序共享相同的DLL,因此如果DLL中的代码或数据发生问题,则可以在一次更新后修复所有使用该DLL的应用程序。

        使用DLL的过程分为两个步骤:首先需要创建一个DLL,然后在需要使用该DLL的应用程序中加载它。为了使DLL中的函数可以在应用程序中使用,必须将其导出,可以使用__declspec(dllexport)修饰符来导出DLL中的函数和数据。而在应用程序中调用DLL中的函数,需要使用LoadLibrary()函数来加载DLL,并使用GetProcAddress()函数获取DLL中导出函数的地址,然后使用函数指针来调用这些函数。

        在Linux下,与之对应的是.so文件。MacOs下为.dylib。

二、C++制作DLL文件

        需要打开你的windows Visual Satdio任意版本。可以直接选择创建DLL文件,也可以先创建平台程序后续再改。

        这里直接展示一段简单的代码。

2.1 DLL端

        DllDLL.h:

#pragma once
#ifdef MYLIBRARY_EXPORTS
#define MYLIBRARY_API __declspec(dllexport)
#else
#define MYLIBRARY_API __declspec(dllimport)
#endifMYLIBRARY_API int Add(int a, int b);

        DllDLL.cpp:

#include "DllDLL.h"int Add(int a, int b)
{return a + b;
}

        DllDLL.def模块定义:

LIBRARY GeneratrDLL
EXPORTS
Add @1

        模块定义需要在这设定:

重点:

.def文件(也称为导出文件)是一种Windows平台上的文件格式,用于描述可执行文件或动态链接库(DLL)中导出函数的名称和地址。当编写一个DLL并将其与其他应用程序链接时,该DLL中的函数必须明确导出,以便其他应用程序能够调用这些函数。

2.2 调用端

代码:

#include "..\DllDLL\DllDLL.h"
#include <windows.h>
#include <iostream>
typedef int(*AddFunc)(int, int);int main()
{HINSTANCE hinstLib = LoadLibrary(TEXT("DllDLL.dll"));if (hinstLib != NULL){AddFunc add = (AddFunc)GetProcAddress(hinstLib, "Add");if (add != NULL){// 调用 DLL 中的函数int result = add(1, 2);std::cout << result << std::endl;}}}

将UseDllDLL设置为启动项,运行结果(DLL内部返回方法的结果):

三、DLL导出类方法

        我们定义一个MyInterface基类,里面实现虚方法,再生成一个它的派生类实现虚方法,最后创建类工厂让客户端代码更容易实例化类对象。

// MyInterface.h
#ifndef MY_INTERFACE_H
#define MY_INTERFACE_Hclass MyInterface
{
public:virtual ~MyInterface(){}virtual void DoSomething() = 0;virtual int GetNumber() = 0;
};class MyImplementation : public MyInterface
{
public:virtual void DoSomething() override;virtual int GetNumber() override;
};
#endif // MY_INTERFACE_H// MyImplementation.cpp
#include "MyInterface.h"void MyImplementation::DoSomething()
{//
}int MyImplementation::GetNumber()
{return 49;
}// MyDLL.h
#ifndef MY_DLL_H
#define MY_DLL_H#ifdef MY_DLL_EXPORTS
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif#include "MyInterface.h"MY_DLL_API MyInterface* CreateMyObject();#endif // MY_DLL_H// MyDLL.cpp
#define MY_DLL_EXPORTS
#include "MyDLL.h"
#include "MyInterface.h"MyInterface* CreateMyObject()
{return new MyImplementation();
}

        上面代码的最后两端将MyInterface* 类的对象作为导出接口,它的我实现是返回它的派生类MyImplementation类的实例对象。客户端可以使用CreateMyObject获得实例。

        客户端调用DLL,首先要有实现DLL的头文件MyInerface.h,然后去调用,具体:

#include "..\GeneratrDLL\MyInterface.h"
#include <Windows.h>
#include <iostream>int main()
{// 加载DLLHMODULE hModule = LoadLibrary(L"C:\\Users\\liubw\\source\\repos\\GeneratrDLL\\x64\\Debug\\GeneratrDLL.dll");if (hModule != NULL){// 获取接口typedef MyInterface* (*CreateMyObjectFunc)();CreateMyObjectFunc fun = (CreateMyObjectFunc)GetProcAddress(hModule, "CreateMyObject");if (fun != NULL){// 使用接口MyInterface* myObject = createMyObject();myObject->DoSomething();int number = myObject->GetNumber();std::cout << number << std::endl;delete myObject;}else{// 无法获取接口}// 卸载DLLFreeLibrary(hModule);}else{// 无法加载DLL}return 0;
}

 其中typedef MyInterface* (*CreateMyObjectFunc)();声明了MyInterface*函数指针的函数CreateMyObjectFunc,并且没有参数,我们可以用CreateMyObjectFunc代替返回值为MyInterface*的函数的声明。具体如下:

https://bobowen.blog.csdn.net/article/details/129189507?spm=1001.2014.3001.5502

四、COM技术制作DLL

        这个是老技术,比较复杂,后续更新。

相关文章:

【C++】Windows动态库【.DLL文件】制作方法总结

如题&#xff0c;我们本篇介绍如何制作DLL&#xff0c;将代码类中的方法以接口的形式暴露出来给exe程序使用。会涉及类厂创建方法实例、声明DLL接口、.def文件的使用等。 目录 一、DLL介绍 二、C制作DLL文件 2.1 DLL端 2.2 调用端 三、DLL导出类方法 四、COM技术制作DLL…...

C 语言编程 — HelloWorld

目录 文章目录目录安装 Linux GCC 编译器YUM 安装发行版本编译安装指定版本HelloWorld基本语法编码运行安装 Linux GCC 编译器 YUM 安装发行版本 $ yum install gcc vim -y$ gcc --version gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) Copyright © 2015 Free Software…...

蓝桥杯入门即劝退(二十一)三数之和(梦破碎的地方)

欢迎关注点赞评论&#xff0c;共同学习&#xff0c;共同进步&#xff01;------持续更新蓝桥杯入门系列算法实例--------如果你也喜欢Java和算法&#xff0c;欢迎订阅专栏共同学习交流&#xff01;你的点赞、关注、评论、是我创作的动力&#xff01;-------希望我的文章对你有所…...

element 下拉框支持搜索并输入

前言 下拉框对于开发来说再常见不过了&#xff0c;也是界面设计中的常用组件&#xff0c;在部分使用场景下&#xff0c;我们需要做到下拉框可以选择的同时&#xff0c;支持搜素和输入&#xff0c;以 element 的下拉框组件为例&#xff0c;当我们同时设置属性让其支持搜素和输入…...

JVM详解——垃圾回收

如果有兴趣了解更多相关内容的话&#xff0c;可以看看我的个人网站&#xff1a;耶瞳空间 GC&#xff1a;垃圾收集(Gabage Collection)&#xff0c;内存处理是编程人员容易出现问题的地方&#xff0c;忘记或者错误的内存。不当的回收可能会导致程序或系统的不稳定甚至崩溃&…...

spring之集成Mybatis

文章目录一、实现步骤1、准备数据库表2、在IDEA中创建一个模块&#xff0c;并引入依赖3、基于三层架构实现4、编写pojo5、编写mapper接口6、编写mapper配置文件7、编写service接口和service接口的实现类8、编写jdbc.properties配置文件9、编写mybatis-config.xml配置文件10、编…...

【面试宝典】准备面试了~集合

1、ArrayList和linkedList的区别 它们都是继承自 Collection。 ArrayList 是基于数组的&#xff0c;在使用查询的时候效率比较高&#xff0c;但删除效率却非常低&#xff0c;因为它需要重新排数组中的所有数据。 LinkList底层是一个双链表&#xff0c;在添加和删除元素时更好…...

华为OD机试真题Python实现【GPU 调度】真题+解题思路+代码(20222023)

GPU 调度 题目 为了充分发挥 GPU 算力, 需要尽可能多的将任务交给 GPU 执行, 现在有一个任务数组, 数组元素表示在这1s内新增的任务个数, 且每秒都有新增任务, 假设 GPU 最多一次执行n个任务, 一次执行耗时1s, 在保证 GPU 不空闲的情况下,最少需要多长时间执行完成。…...

gcc编译C源程序

一、安装 在Linux下&#xff0c;一般使用gcc或arm-linux-gcc交叉编译器来编译程序。在Ubuntu环境下&#xff0c;我们可以使用以下apt-get命令来安装这些编译程序。 apt-get install gcc apt-get install gcc-arm-linux-gnueabi 安装完毕后&#xff0c;使用以下命令查看编译器…...

Tina_Linux_各平台多媒体格式_支持列表_new

Tina Linux 各平台多媒体格式支持列表 1 概述 1.1 编写目的 本文档将介绍Allwinner Tina Linux 系统各个芯片平台支持的多媒体格式&#xff0c;旨在帮助软件开发工程师、技术支持工程师查找各芯片平台支持哪些多媒体格式。 1.2 适用范围 Tina Linux v3.5 及以上版本。 1.…...

归并排序及其应用

归并排序算法基于分而治之的概念&#xff0c;具体来说就是遍历一棵树&#xff0c;归并的过程是一个后序执行的动作。 由于我们知道每个子部分在合并后都是有序的&#xff0c;我们可以利用这个特性来解决一些问题。 上图可视化了merge sort algorithm的过程&#xff0c;我们很容…...

【PAT甲级题解记录】1007 Maximum Subsequence Sum (25 分)

【PAT甲级题解记录】1007 Maximum Subsequence Sum (25 分) 前言 Problem&#xff1a;1007 Maximum Subsequence Sum (25 分) Tags&#xff1a;DP Difficulty&#xff1a;剧情模式 想流点汗 想流点血 死而无憾 Address&#xff1a;1007 Maximum Subsequence Sum (25 分) 问题描…...

华为OD机试真题Python实现【 最小叶子节点】真题+解题思路+代码(20222023)

最小叶子节点 题目 二叉树也可以用数组来存储, 给定一个数组,树的根节点的值储存在下标1, 对于储存在下标n的节点,他的左子节点和右子节点分别储存在下标2*n和2*n+1, 并且我们用-1代表一个节点为空, 给定一个数组存储的二叉树, 试求从根节点到最小的叶子节点的路径, …...

mars3d动态轨迹DynamicRoamLine,如何获取实时运⾏的经纬度

问题 1.期望 实现 实时显示经纬度、⾼度&#xff0c;做电⼦围栏报警判断 2.第⼀步就是要&#xff0c;获取实时运⾏的经纬度信息、⾼度信息&#xff0c;然后通过算法做电⼦围栏判断 3.使⽤了参数getOverPositions&#xff0c;发现返回的不是经纬度 相关链接 http://mars3d.cn//e…...

jvm常识

Jvm工作原理学习笔记0126一、JVM的生命周期1.JVM实例对应了一个独立运行的java程序它是进程级别a)启动。启动一个Java程序时&#xff0c;一个JVM实例就产生了&#xff0c;任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点b)运行。ma…...

PHP部署、nginx与PHP的整合、PHP动态添加模块

文章目录前言一、基本知识1.php介绍2.PHP能做什么3.web工作原理4.PHP脚本主要用于领域5.php其他相关信息6.memcache介绍二、php的源码安装1.php安装2.php配置三、nginx与php整合四、php动态扩展模块&#xff08;memcache模块&#xff09;前言 一、基本知识 1.php介绍 官方下载…...

SpringCloud与SpringBoot的版本对应

一、SpringCloud与SpringBoot的版本对应 SpringCloud版本 SpringBoot版本 2021.0.1-SNAPSHOT Spring Boot >2.6.4-SNAPSHOT and <2.7.0-M1 2021.0.0 Spring Boot >2.6.1 and <2.6.4-SNAPSHOT 2021.0.0-RC1 Spring Boot >2.6.0-RC1 and <2.6.1 2021.0.0-M3 Sp…...

华为OD机试题,用 Java 解【N 进制减法】问题

最近更新的博客 华为OD机试 - 猴子爬山 | 机试题算法思路 【2023】华为OD机试 - 分糖果(Java) | 机试题算法思路 【2023】华为OD机试 - 非严格递增连续数字序列 | 机试题算法思路 【2023】华为OD机试 - 消消乐游戏(Java) | 机试题算法思路 【2023】华为OD机试 - 组成最大数…...

Linux->进程概念于基本创建

1. 进程基本概念 当一个可执行程序被加载到内存当中&#xff0c;并由操作系统将其管理起来&#xff0c;此时这个程序就被称之为进程。也就是下方的&#xff1a; 程序的一个执行实例&#xff0c;正在执行的程序等 担当分配系统资源&#xff08;CPU时间&#xff0c;内存&#xff…...

【MySQL】5.7版本解压安装配置

前言 之所以使用解压版本&#xff0c;而不使用exe安装&#xff0c;因为exe的安装方式删除过于麻烦&#xff01;&#xff01;&#xff01; 如果安装MySQL过程中&#xff0c;出错了或者想重新在来一把&#xff0c;删除mysql服务即可 sc delete mysql # 删除已经安装好的Mysql&a…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下&#xff0c;企业和个人创作者为了扩大影响力、提升传播效果&#xff0c;纷纷采用短视频矩阵运营策略&#xff0c;同时管理多个平台、多个账号的内容发布。然而&#xff0c;频繁的文案创作需求让运营者疲于应对&#xff0c;如何高效产出高质量文案成…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...