C++制作DLL文件的方法详解

 更新时间:2023年04月25日 10:14:51   作者:Thomas_Lbw  
本文主要介绍如何制作DLL,将代码类中的方法以接口的形式暴露出来给exe程序使用。会涉及类厂创建方法实例、声明DLL接口、.def文件的使用等,感兴趣的可以了解一下

一、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)
#endif
 
MYLIBRARY_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_H
 
class 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()
{
	// 加载DLL
	HMODULE 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
		{
			// 无法获取接口
		}
 
		// 卸载DLL
		FreeLibrary(hModule);
	}
	else
	{
		// 无法加载DLL
	}
 
	return 0;
}

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

【C/C++】中【typedef】用法大全

以上就是C++制作DLL文件的方法详解的详细内容,更多关于C++制作DLL文件的资料请关注脚本之家其它相关文章!

相关文章

  • 在C++中实现云端存储变量的操作步骤

    在C++中实现云端存储变量的操作步骤

    随着云计算技术的快速发展,现在我们可以将数据存储在云端,以便于在不同设备和地点访问,在C++中,我们也可以通过一些方法来实现这个功能,本文将详细介绍如何在C++中实现云端存储变量,需要的朋友可以参考下
    2023-11-11
  • c语言如何实现两数之和

    c语言如何实现两数之和

    这篇文章主要介绍了c语言如何实现两数之和,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C++超详细讲解泛型

    C++超详细讲解泛型

    泛型编程,故如其名,是一个泛化的编程方式。其实现原理为程序员编写一个函数/类的代码示例,让编译器去填补出不同的函数实现
    2022-07-07
  • 记逆向小白的第一次vbsedit 9爆破及内存补丁制作过程

    记逆向小白的第一次vbsedit 9爆破及内存补丁制作过程

    这篇文章主要介绍了记逆向小白的第一次vbsedit 9爆破及内存补丁制作过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • C++基于Floyd算法实现校园导航系统

    C++基于Floyd算法实现校园导航系统

    这篇文章主要为大家详细介绍了C++基于Floyd算法实现校园导航系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C++ new与malloc和delete及free动态内存管理及区别介绍

    C++ new与malloc和delete及free动态内存管理及区别介绍

    这篇文章主要介绍了深入理解C++中的new/delete和malloc/free动态内存管理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-12-12
  • 深度剖析C语言结构体

    深度剖析C语言结构体

    今天小编就为大家分享一篇关于深度剖析C语言结构体,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C语言实现游戏VIP停车场管理系统

    C语言实现游戏VIP停车场管理系统

    这篇文章主要介绍了C语言实现游戏VIP停车场管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • c++ 头文件<cwchar>中常见函数的实现代码

    c++ 头文件<cwchar>中常见函数的实现代码

    本文记录了c++ 头文件<cwchar>中常见函数的实现,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • C++ 内联函数inline案例详解

    C++ 内联函数inline案例详解

    这篇文章主要介绍了C++ 内联函数inline案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09

最新评论