动态链接编程 学习笔记

创建动态链接库项目



导出


一.使用DEF

在DLL库文件的头文件中使用extern "C" 申明

cpp 复制代码
//方法一,导出函数,配合def文件
extern "C" void DefTest1();
extern "C" void DefTest2();

在cpp文件中实现

cpp 复制代码
//方法一,导出函数,配合def文件
extern "C" void DefTest1()
{
	AfxMessageBox(_T("DefTest1 is called"));
}

extern "C" void DefTest2()
{
	AfxMessageBox(_T("DefTest2 is called"));
}

在def文件中声明

cpp 复制代码
; MFCLibrary1.def: 声明 DLL 的模块参数。

LIBRARY MFCLibrary1
    ; LIBRARY + DLL名字

EXPORTS
DefTest1 @ 1
DefTest2 @ 2
    ; 此处可以是显式导出

二、使用关键字__declspec(dllexport)导出函数

在DLL库文件的头文件中使用extern "C" 申明

cpp 复制代码
//方法二,使用关键字导出
//__declspec(dllexport)<返回类型><导出函数名>(<函数参数>)
extern "C" __declspec(dllexport) void dllExportTest3();

在cpp文件中实现

cpp 复制代码
//方法二,使用关键字导出
//__declspec(dllexport)<返回类型><导出函数名>(<函数参数>)
extern "C" __declspec(dllexport) void dllExportTest3()
{
	AfxMessageBox(_T("__declspec(dllexport) void dllExportTest3() called"));
}

三、使用关键字__declspec(dllexport)导出类

在DLL库文件的头文件中使用extern "C" 申明

cpp 复制代码
//导出类
//class __declspec(dllexport)<导出类名>[:public <基类名>]{...}
extern "C" class __declspec(dllexport) CMFCLibrary1
{
public:
	CMFCLibrary1();
	void show();

};

在cpp文件中实现

cpp 复制代码
//导出类实现
// CMFCLibrary1App 构造
CMFCLibrary1::CMFCLibrary1()
{
	// TODO:  在此处添加构造代码,
	// 将所有重要的初始化放置在 InitInstance 中
}



void CMFCLibrary1::show()
{
	AfxMessageBox(_T("CMFCLibrary1App::show()"));
}


使用动态链接库项目

新建项目

导入

一、使用隐式链接

隐式链接又称静态加载,需要DLL和LIB文件。在程序退出前,DLL一直存在该程序运行的地址空间中。

A.使用.LIB文件和.H文件
1)加载lib文件和h文件
2)在使用处的cpp文件中添加头文件引用
cpp 复制代码
#include "MFCLibrary1.h"
3)调用DLL中的函数
cpp 复制代码
void CDllTestDlg::OnBnClickedButton1()
{
	edit1 = "OnBnClickedButton1()";
	//AfxMessageBox(_T("OnBnClickedButton1()"));
	DefTest1();
	UpdateData(false);
}


void CDllTestDlg::OnBnClickedButton2()
{
	edit1 = "OnBnClickedButton2()";
	DefTest2();
	UpdateData(false);
}

B.使用.LIB文件和 __declspec(dllimport)导入语句
1)加载lib文件
2)在使用处的cpp文件中添加函数导入语句
cpp 复制代码
extern "C" __declspec(dllimport) void DefTest1();
extern "C" __declspec(dllimport) void DefTest2();
extern "C" __declspec(dllimport) void dllExportTest3();
3)调用DLL中的函数
cpp 复制代码
void CDllTestDlg::OnBnClickedButton1()
{
	edit1 = "OnBnClickedButton1()";
	//AfxMessageBox(_T("OnBnClickedButton1()"));
	DefTest1();
	UpdateData(false);
}


void CDllTestDlg::OnBnClickedButton2()
{
	edit1 = "OnBnClickedButton2()";
	DefTest2();
	UpdateData(false);
}


void CDllTestDlg::OnBnClickedButton3()
{
	edit1 = "OnBnClickedButton3()";
	dllExportTest3();
	UpdateData(false);
}

C.使用.LIB文件和#pragma comment(lib, "***.lib")加载语句

#pragma comment(lib, "***.lib")加载语句 效果等同于通过添加现有文件方式添加lib文件

1)加载h文件
2)在pch.h文件中添加lib加载语句
cpp 复制代码
#pragma comment(lib, "MFCLibrary1.lib")
3)在CPP文件中引用头文件
cpp 复制代码
#include "MFCLibrary1.h"
4)调用DLL中的函数
cpp 复制代码
void CDllTestDlg::OnBnClickedButton4()
{
	UpdateData();
	CMFCLibrary1 lib{};
	edit1 = "OnBnClickedButton4()";
	UpdateData(false);
	lib.show();
}

二、使用显示链接

动态又称动态加载,必须在代码中动态地加载所使用的DLL,并使用指针调用DLL中的导出函数,在使用完毕后,必须卸载所使用的DLL。

加载DLL,LoadLibrary()、AfxLoadLibrary()

获取函数地址,GetProcAddress()、AfxGetProcAddress()

释放DLL,FreeLibrary()、AfxFreeLibrary()

A.动态加载函数
cpp 复制代码
void CDllTestDlg::OnBnClickedButton3()
{
	UpdateData();
	edit1 = "OnBnClickedButton3()";
	UpdateData(false);

	//显式链接到 DLL,并返回该 DLL 的句柄
	HINSTANCE hinst = NULL;
	hinst = LoadLibrary(_T("MFCLibrary1.dll"));
	if (hinst == NULL)
	{
		return;
	}

	//从指定的动态链接库 (DLL) 检索导出函数 (也称为过程) 或变量的地址。
	FARPROC lpfn = NULL;
	lpfn = GetProcAddress(hinst, "dllExportTest3");
	if (lpfn == NULL)
	{
		return;
	}

	typedef void(*Fun3)();//函数指针
	Fun3 fun3 = (Fun3)lpfn;
	if (fun3 == nullptr)
	{
		return;
	}
	lpfn();

	//释放加载的动态链接库 (DLL) 模块,并在必要时递减其引用计数
	FreeLibrary(hinst);
}

B.动态加载类

需要.h文件和dll文件,参考https://edu.51cto.com/article/note/12964.html

定义接口,通过接口派生类。

1.定义DLL库
cpp 复制代码
// MFCLibrary1.h: MFCLibrary1 DLL 的主标头文件
//

#pragma once

#ifndef __AFXWIN_H__
	#error "在包含此文件之前包含 'pch.h' 以生成 PCH"
#endif

#include "resource.h"		// 主符号
#include <string>



//导出类
//class __declspec(dllexport)<导出类名>[:public <基类名>]{...}
class __declspec(dllexport) MyInterface
{
public:
	virtual void show() = 0;
	virtual void show(const CString& s)=0;
	virtual ~MyInterface() {}
};
cpp 复制代码
// MFCLibrary1.cpp: 定义 DLL 的初始化例程。
//

#include "pch.h"
#include "framework.h"
#include "MFCLibrary1.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


class MyClass : public MyInterface
{
public:
	virtual void show() override
	{
		AfxMessageBox(_T("MyClass::show() called"));
	}

	virtual void show(const CString& s) override
	{
		AfxMessageBox(s);
	}

	~MyClass() {}
};


extern "C" __declspec(dllexport) MyInterface * createPrinter()
{
	return new MyClass();
}

extern "C" __declspec(dllexport) void deletePrinter(MyInterface * printer)
{
	delete printer;
}
2.复制必要文档到跟目录,把.H文件添加到库
3.CPP中加载并获取类的创建函数指针,使用后回收资源并删除动态分配
cpp 复制代码
void CDllTestDlg::OnBnClickedButton4()
{
	UpdateData();

	edit1 = "OnBnClickedButton4()";
	UpdateData(false);

	//显式链接到 DLL,并返回该 DLL 的句柄
	HINSTANCE hinst = NULL;
	hinst = LoadLibrary(TEXT("MFCLibrary1.dll"));
	if (hinst == NULL)
	{
		return;
	}

	//从指定的动态链接库 (DLL) 检索导出类的地址。
	typedef MyInterface* (*CreatePrinter)();
	CreatePrinter createPrinter = (CreatePrinter)GetProcAddress(hinst, "createPrinter");
	if (createPrinter == nullptr)
	{
		return;
	}

	MyInterface* myClass = createPrinter();//实例化类

	//测试类的功能
	if (myClass)
	{
		myClass->show();
		CString s = {TEXT("OnBnClickedButton4() called")};
		myClass->show(s);
	}

	//删除动态分配
	typedef void (*DeletePrinter)(MyInterface*);
	DeletePrinter deletePrinter = (DeletePrinter)GetProcAddress(hinst, "deletePrinter");
	deletePrinter(myClass);

	//释放加载的动态链接库 (DLL) 模块,并在必要时递减其引用计数
	FreeLibrary(hinst);
}
相关推荐
q***T5831 小时前
GitHub星标20万+的React项目,学习价值分析
前端·学习·react.js
小此方1 小时前
笔记:树。
数据结构·笔记
小马爱打代码2 小时前
Consul:系统学习笔记
笔记·学习·consul
LastWhisperw3 小时前
简历填写Agent开发笔记
笔记
会编程的李较瘦4 小时前
【Spark学习】数据清洗
学习·ajax·spark
RisunJan4 小时前
【行测】实词辨析
学习
m0_626535205 小时前
双线性插值学习
学习
YJlio5 小时前
进程和诊断工具学习笔记(8.24):Handle——谁占着不放?句柄泄漏排查、强制解锁与检索技巧
服务器·笔记·学习
charlie1145141915 小时前
面向C++程序员的JavaScript 语法实战学习4
开发语言·前端·javascript·学习·函数