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

动态库dll与静态库lib编程3:DLL导出函数的调用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、说明
    • 1.1隐式链接说明
    • 1.2显式链接说明
  • 二、具体实现
    • 2.1隐式链接具体实现
    • 2.2显式链接具体实现
  • 总结


前言

动态库dll与静态库lib编程3:DLL导出函数的调用。.exe程序如何调用DLL中的导出函数进行使用


一、说明

调用DLL的导出函数的方法有两种:

1.1隐式链接说明

隐式链接的特点是由编译器完成对DLL的加载和程序结束时对DLL的卸载工作,如果程序结束时还有其他应用程序使用该DLL,那么系统会使DLL的使用计数减1,当DLL的使用计数为0时,会将DLL从内存中删除。
优缺点:隐式链接DLL的方法简单实用,但缺少灵活性。编程者无法控制DLL的加载和卸载。
使用方法:使用隐式链接DLL开发时,首先需要将DLL的引入库文件(* .lib编译生成DLL时,会一起生成的),与应用程序进行静态链接,因为引入库文件包含DLL的各种输出资源,如导出函数、导出类等信息,这些信息指向DLL的函数指针等,.exe执行时,DLL被“自动”加载,.exe退出时,DLL被“自动”卸载。

1.2显式链接说明

显式链接方式是完全由编程者使用API加载和卸载DLL,编程者可以决定何时加载DLL,加载哪个DLL,何时卸载DLL,卸载哪个DLL。
优缺点:显式链接方式充分体现了DLL的灵活性,是比较常用的调用DLL方式,但是与隐式链接相比复杂了些。
使用方法:LoadLibrary(),该API用于加载指定的DLL;
GetProcAddress(),该API用于获取DLL中导出函数的指针,即导出函数的入口点;
FreeLibrary(),该API用于卸载指定的DLL。
注意:1.如果程序中多次调用LoadLibrary()加载同一个DLL,那么在卸载的时候也要调用相应次数的FreeLibrary()进行卸载。2.使用LoadLibrary显式链接,在这个函数的参数中可以指定DLL文件的路径,如果不指定路径,Windows将遵循如下的搜索顺序来定位DLL:.exe文件所在目录->进程的当前工作目录->Windows系统目录,如C:\WINDOWS\system32->Windows目录,如C:\WINDOWS->环境变量的目录

说明:1.进程的当前工作目录,使用函数SetCurrentDirectory()设置的路径,或者从父进程继承而来的路径,使用GetCurrentDirectory()得到。2…exe文件所在的目录,本.exe文件所在的绝对路径,使用GetModuleFileName得到,两者可能不同。3.GetProcAddress()函数可以有两种方式取得DLL导出函数的入口点:

GetProcAddress(hMod, "add"); // 按照函数名方式
GetProcAddress(hMod, MAKEINTRESOURCEA(1)); // 按照导出函数序号方式

二、具体实现

2.1隐式链接具体实现

利用之前生成的DllTest工程,DllTest工程的生成见https://blog.csdn.net/qq_59940419/article/details/144721964?spm=1001.2014.3001.5502。
在工程目录下可见生成的* .dll文件和* .lib文件。
在这里插入图片描述
接下来在同一解决方案下新建一个调用动态链接库的工程,即生成.exe的工程。
右键解决方案,选择添加->新建项目
在这里插入图片描述
选择控制台应用,随意命名即可。这将生成一个.exe控制台程序
在这里插入图片描述
由于DllTest生成动态链接库,不能自己执行,只能被.exe程序调用,因此需要将DllCall项目工程设为启动项目。这里与静态链接库类似,见https://blog.csdn.net/qq_59940419/article/details/144694027?spm=1001.2014.3001.5502
在这里插入图片描述
第一步:将DLL的引入库文件(* .lib编译生成DLL时,会一起生成的),与应用程序进行静态链接

#pragma comment(lib, "..\\Debug\\DllTest.lib") //将DLL的引入库文件(* .lib编译生成DLL时,会一起生成的),与应用程序进行静态链接

编译成功则说明链接成功

第二步:将函数add进行声明导入,这里只导入add函数,dec函数用作显式链接示例。

_declspec(dllimport) int add(int a, int b); //将函数进行声明导入,隐式链接

之后即可在DllCall中使用函数add
完整的DllCall.cpp代码如下

// DllCall.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
using namespace std;
#pragma comment(lib, "..\\Debug\\DllTest.lib") //将DLL的引入库文件(* .lib编译生成DLL时,会一起生成的),与应用程序进行静态链接
_declspec(dllimport) int add(int a, int b); //将函数进行声明导入,隐式链接


int main()
{
    std::cout << add(1, 3)<<endl;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

输出为
在这里插入图片描述

2.2显式链接具体实现

用显式链接具体实现dec函数的导入。由于使用显式链接的三个函数,需要在DllCall.cpp源文件中引入头文件:#include<Windows.h>;而为了使用_T,需要添加#include <tchar.h>
显式链接代码如下

	HMODULE hMod = LoadLibrary(_T("..\\Debug\\DllTest.dll")); // 加载指定的DLL,参数为DLL路径(要用宽字节字符串),由于支持Unicode编码,用_T进行宽字节类型转换。返回值为DLL在进程空间中的句柄,
	if (hMod) // hMod非NULL,才进行后续操作
	{
		DEC_FUNC dec_fp = (DEC_FUNC)GetProcAddress(hMod, "dec"); // 获取函数dec指针,这里的第二个参数要用窄字节字符串;返回值为导出函数的入口点地址
		if (dec_fp) // dec_fp非NULL,才进行后续操作
		{
			cout << dec_fp(10, 7) << endl; // 直接使用函数
		}
		FreeLibrary(hMod); // 与LoadLibrary对应,卸载指定的DLL
	}

则整个DllCall.cpp为

// DllCall.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<Windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "..\\Debug\\DllTest.lib") //将DLL的引入库文件(* .lib编译生成DLL时,会一起生成的),与应用程序进行隐式链接
_declspec(dllimport) int add(int a, int b); //将函数进行声明导入,隐式链接


typedef int(*DEC_FUNC)(int a, int b); // 定义显式链接的函数指针类型DEC_FUNC

int main()
{
	// 隐式链接add
    std::cout << add(1, 3)<<endl;
	//显式链接dec
	HMODULE hMod = LoadLibrary(_T("..\\Debug\\DllTest.dll")); // 加载指定的DLL,参数为DLL路径(要用宽字节字符串),由于支持Unicode编码,用_T进行宽字节类型转换。返回值为DLL在进程空间中的句柄,
	if (hMod) // hMod非NULL,才进行后续操作
	{
		DEC_FUNC dec_fp = (DEC_FUNC)GetProcAddress(hMod, "dec"); // 获取函数dec指针,这里的第二个参数要用窄字节字符串;返回值为导出函数的入口点地址
		if (dec_fp) // dec_fp非NULL,才进行后续操作
		{
			cout << dec_fp(10, 7) << endl; // 直接使用函数
		}
		FreeLibrary(hMod); // 与LoadLibrary对应,卸载指定的DLL
	}
}

可以正常运行
在这里插入图片描述


总结

动态库dll与静态库lib编程3:DLL导出函数的调用


http://www.kler.cn/a/466239.html

相关文章:

  • 深度学习笔记10-数据增强(Tensorflow)
  • 在Vue3项目中使用svg-sprite-loader
  • Gitee 的基本用法
  • 查看打开的端口
  • 【JavaWeb后端学习笔记】MySQL的数据控制语言(Data Control Language,DCL)
  • 多线程访问FFmpegFrameGrabber.start方法阻塞问题
  • SkyWalking概述
  • 谷歌浏览器的高级安全设置使用方法
  • 整数拼接(哈希表 枚举)
  • docker基本概念,docker镜像管理,docker命令
  • zookeeper+kafka
  • 深入剖析MySQL数据库架构:核心组件、存储引擎与优化策略(四)
  • matlab系列专栏-matlab概述
  • xdoj 出现次数最多的数
  • WPF 数据绑定中的通知机制及其性能考虑
  • Android多渠道打包【友盟方式详细讲解版】
  • 《Opencv》基础操作详解(4)
  • python实现,outlook每接收一封邮件运行检查逻辑,然后发送一封邮件给指定邮箱
  • 单片机按键扫描程序,可以单击、双击、长按,使用状态机,无延时,不阻塞。
  • JavaScript中的“==”和“===”有什么区别