生成DLL的方法

本文深入讲解动态链接库(DLL)的导出机制,包括函数、全局变量、类及类对象指针的导出方法,同时介绍了MFC扩展DLL的创建过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于DLL

DLL(Dynamic Linkable Library),动态链接库,可以向程序提供一些函数、变量或类。这些可以直接拿来使用。

静态链接库与动态链接库的区别:

(1)静态链接库与动态链接库都是共享代码的方式。静态链接库把最后的指令都包含在最终生成的EXE文件中了;动态链接库不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。

(2)静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

动态链接库的分类:Visual C++支持三种DLL,它们分别是:

(1)Non-MFC DLL(非MFC动态库):

非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;

(2)MFC Regular DLL(MFC规则DLL):

MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;

(3)MFC Extension DLL(MFC扩展DLL):

MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。

借用一下别人的简介: 原文链接:https://blog.youkuaiyun.com/u014066037/article/details/82491481

导出DLL

生成DLL文件,导出函数,一般有两种方法,一种是在函数声明前面加上__declspec(dllexport),另一种是用def文件来动态导出函数。接下来我将介绍三种使用__declspec(dllexport)导出DLL的方法。

导出函数和全局变量

新建一个普通的控制台空项目,新建头文件声明函数,源文件定义函数,导出函数时常在头文件 使用__declspec(dllexport) 声明要导出的函数

// An highlighted block
//
extern "C" __declspec(dllexport) int Add(int a, int b);

函数定义并没有什么特别,但使用DLL时 ,需要使用__declspec(dllimport) 声明导入的函数

// An highlighted block
#include <iostream>
using namespace std;
//lib文件,相当于导出函数的目录
#pragma comment(lib,"DynamicLib")
//声明导入的函数
extern "C"  _declspec(dllimport) int Add(int a, int b);
int main()
{
    Add(1,2);
    return 0;
}

为了方便使用,可以将导出导入声明都写入头文件。导出函数的步骤如下:
1.新建头文件 func.h

// An highlighted block
#pragma once

#ifdef _DLL_EXPORTS
#define DLL_API _declspec(dllexport)
#else
#define DLL_API _declspec(dllimport)
#endif
//将_DLL_EXPORTS定义在源文件
extern "C" DLL_API int Add(int a, int b);
//导出函数,extern表示变量定义在别的地方
DLL_API extern int  intArray[512];

2.定义源文件 func.cpp

// An highlighted block
//  func.cpp: 定义 DLL 应用程序的导出函数。
#define _DLL_EXPORTS
#include "func.h"
//定义变量
int  intArray[512];
int Add(int a,int b)
{
	return a+b;
}

3.在解决方案下项目上右键属性–》配置属性–》常规–》配置类型,将类型由应用程序(exe)改为动态库(.dll)
在这里插入图片描述

4.重新生成项目,生成成功。我用的是 release配置方案,所以在 release文件夹下找到dll文件与lib文件
5.使用DLL。简单试一下DLL文件。将 头文件 func.h,dll文件,lib文件,放入,需要使用项目文件下。我是放在与main.cpp文件相同文件夹下。

// 测试导出的函数
#include <iostream>
#include "func.h"
using namespace std;
//导入生成的lib文件
#pragma comment(lib,"DLL.lib")

int main()
{
	cout<<Add(1,2)<<endl;
	return 0;
}

导出类

1.同样声明头文件Stu.h,只需要在导出类名前关键字class后加上_declspec(dllexport),就可以实现导出类

// An highlighted block
#pragma once
#ifdef _DLL_StuEXPORTS
#define DLL_StuAPI _declspec(dllexport)
#else
#define DLL_StuAPI _declspec(dllimport)
#endif
//只需要在导出类名前关键字class后加上_declspec(dllexport),就可以实现导出类
class DLL_StuAPI Stu
{
public:
	Stu(int a);
	void print();

private:
	int _a;
};

2.定义.cpp文件:

// An highlighted block
// Stu.cpp: 定义 DLL 应用程序的导出函数。
#pragma once
#ifdef _DLL_StuEXPORTS
#define DLL_StuAPI _declspec(dllexport)
#else
#define DLL_StuAPI _declspec(dllimport)
#endif
//只需要在导出类名前关键字class后加上_declspec(dllexport),就可以实现导出类
class DLL_StuAPI Stu
{
public:
	Stu(int a);
	void print();

private:
	int _a;
};

3,4,5步骤与导出函数相同,将调用函数改为调用类对象就行了

这种简单导出类的方式,除了导出的东西太多、使用者对类的实现依赖太多以外,还有其他问题:必须保证使用同一种编译器。导出类的本质是导出类里的函数,因为语法上直接导出了类,没有对函数的调用方式、重命名进行设置,导致了产生的dll并不通用。

导出指向类对象的指针

定义一个抽象类(都是纯虚函数),调用者跟dll共用一个抽象类的头文件,dll中实现此抽象类的派生类,dll最少只需要提供一个用于获取抽象类对象指针的接口。由于是对象一般是通过new分配的,需要我们使用后delete对象,防止内存泄漏。

1.func.h文件:

#pragma once
#ifdef _DLL_AnimalEXPORTS
#define DLL_AnimalAPI _declspec(dllexport)
#else
#define DLL_AnimalAPI _declspec(dllimport)
#endif

class IAnimal
{
public:
	virtual void eat() = 0;
	virtual void delObj() = 0;
};
extern "C" DLL_AnimalAPI IAnimal *GetCat();

2…cpp文件:

#define _DLL_AnimalEXPORTS
#include "Animal.h"

#include <iostream>
using namespace std;

class Cat :public IAnimal
{
public:
	Cat()
	{
		cout << "Cat is created" << endl;
	}
	~Cat()
	{
		cout << "Cat is deleted" << endl;
	}
	virtual void eat()
	{
		cout << "Cats eat fish" << endl;
	}
	virtual void delObj()
	{
		delete this;
	}
};
IAnimal *GetCat()
{
	return new Cat;
}

3,4,5步骤与导出函数相同
调用者代码:

//测试导出的类指针
#include <iostream>
#include "Animal.h"
using namespace std;
//导入生成的lib文件
#pragma comment(lib,"DLL.lib")

int main()
{
	IAnimal *cat=GetCat();
	cat->eat();
	return 0;
}

//上面的导出类的例子,引用了:https://blog.youkuaiyun.com/qq_33757398/article/details/82229325j

生成 MFC Extension DLL(MFC扩展DLL)

新建MFC DLL项目,应用设置选择MFC拓展DLL
在这里插入图片描述
在这里插入图片描述
2.和普通MFC程序一样,添加窗口资源,窗口类,
在这里插入图片描述
3.修改窗口类头文件,窗口类cpp文件
在导出类名前关键字class后加上AFX_EXT_CLASS,找不到对话框添加,#include “Resource.h”

#pragma once
//找不到对话框查看是否添加,#include "Resource.h"
#include "Resource.h"

// MydiaLog 对话框
class AFX_EXT_CLASS MydiaLog : public CDialog
{
	DECLARE_DYNAMIC(MydiaLog)

public:
	MydiaLog(CWnd* pParent = NULL);   // 标准构造函数
	virtual ~MydiaLog();

	virtual void OnFinalRelease();

// 对话框数据
	enum { IDD = IDD_DLL_DIALOG };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()
	DECLARE_DISPATCH_MAP()
	DECLARE_INTERFACE_MAP()
public:
	afx_msg void OnBnClickedButton1();
};

4.如果导出静态变量的错误,IMPLEMENT_DYNAMIC(MydiaLog, CDialog)
对话框类头文件修改

//注释掉
// 对话框数据
//	enum { IDD = IDD_DLL_DIALOG };

对话框类,构造函数

MydiaLog::MydiaLog(CWnd* pParent /*=NULL*/)
	: CDialog(MYdialog::IDD, pParent)
{
	EnableAutomation();
}
改为自己的对话框资源IDD
MydiaLog::MydiaLog(CWnd* pParent /*=NULL*/)
	: CDialog(IDD_DLL_DIALOG , pParent)
{
	EnableAutomation();
}

5.使用者函数,导入头文件,lib文件,dll文件

#include "MydiaLog.h"
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
#pragma comment(lib,"MFCDLL") 
...

void CcvMFCDlg::OnBnClickedButton1()
{
	MydiaLog ml;
	ml.DoModal();
	
}

项目文档

项目文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值