动态链接库dll的两种加载方式:隐式和显式

您所在的位置:网站首页 显式方法调用和隐式方法调用的区别 动态链接库dll的两种加载方式:隐式和显式

动态链接库dll的两种加载方式:隐式和显式

2024-07-12 00:41| 来源: 网络整理| 查看: 265

动态链接库的隐式和显式加载 1 前言2 隐式链接----需要.lib,.dll,.h文件2.1 第一种方式(对应上面每种搜索路径1):针对数量较少的库2.2 第二种方式(对应上面每种搜索路径2):针对数量比较多的库(Opencv) 3 显式链接---需要DLL(不需要.lib,.h文件)3.1 **示例1:采用extern “C”的方式**3.2 示例2:_declspec(dllexport) 参考文献

1 前言

在第一篇技术博客动态链接库简介中说到了两种加载方式,当时没有详细说明,这里详细说明一下 可以通过两种方式

隐式链接(需要.dll,.lib,.h)显式链接(需要.dll) 2 隐式链接----需要.lib,.dll,.h文件

隐式链接就是在程序开始执行时就将DLL文件加载到内存当中,而显示链接,是实时加载,程序需要的时候加载,不需要的时候,卸载。 这种方式需要DLL文件,以及相应的Lib文件和头文件。 只要没有在程序中显式链接的,都是隐式链接 Windows程序bin目录包含了可执行文件(.exe)和动态链接库(.dlll),lib目录包含了静态库。 隐式链接步骤: 第一步:将.dll,lib,.h文件放入对应的搜索路径

其中动态库的搜索路径点击这里查看,记住最重要的两个 1. 项目当前目录(.cpp)目录 2. path环境变量中的目录

静态库的搜索路径包括 1. 项目当前目录.cpp目录(项目和解决方案的Debug不行)(也不是解决方案目录) 2. VC设置中的库目录(Library Directories)

在这里插入图片描述

注:如果lib库不放到搜索路径中,也可以在程序中添加

#pragma comment(lib,"D:/DLLTest.lib")//若是相对路径,则为项目当前.cpp目录 头文件搜索路径包括 1. VC设置中的包含目录(Include Directories)

在这里插入图片描述

第二步:一定要在VC设置中的依赖项中添加你用到的库的名字 在这里插入图片描述

2.1 第一种方式(对应上面每种搜索路径1):针对数量较少的库

设置.dll,.lib搜索路径:直接将.dll,.lib,.h放入项目当前目录下(即含有项目源文件.cpp的目录) 在这里插入图片描述 设置.h的搜索路径:VC设置中的包含目录(Include Directories)加入你的.h路径 然后在链接->输入->附加依赖项中加入你要使用的静态库。 这里只添加静态库 在这里插入图片描述 就可以使用DLL中的函数了。

2.2 第二种方式(对应上面每种搜索路径2):针对数量比较多的库(Opencv)

如Opencv,OSG等开源库的配置

这种方式也是通常开源库的配置方式,如Opencv,OSG等

步骤如下:

步骤1.添加DLL的目录

★将dll目录(通常为bin目录)放入环境变量Path中(需要重启),path是搜索动态库的目录

步骤2.添加静态库lib库目录和头文件的目录 在工程中的VC++目录中添加静态库目录和头文件目录。 在这里插入图片描述 步骤3.添加静态库

在链接->输入->附加依赖项中加入你要使用的静态库(当程序中调用时,会在上述配置的库目录中寻找这个库)。 这里只添加静态库,动态库的目录已放入环境变量中,系统会搜索这个路径的,自动加载.dll 如RmwRoadBoundaryStraightLineDLL.lib 然后,在程序中添加头文件 (在上述配置的头文件目录中寻找),就可以使用DLL中的函数了。

3 显式链接—需要DLL(不需要.lib,.h文件)

就是显式加载DLL库 在这里插入图片描述在这里插入图片描述在这里插入图片描述 注意:显示链接,导出DLL的时候,采用extern “C”的方式,而不采用_declspec(dllexport),因为_declspec(dllexport)会有一个”名字改编”的问题(采用了_cdecl调用规约的C++编译方式)。

3.1 示例1:采用extern “C”的方式

如库文件对应的头文件如下

#ifndef DLLTEST_H #define DLLTEST_H //该宏完成在dll项目内部使用__declspec(dllexport)导出 //在dll项目外部使用时,用__declspec(dllimport)导入 //宏DLL_EXPORTS在.cpp中定义 #ifdef DLL_EXPORTS #define DLL_EXPORTS extern"C"_declspec(dllexport) #else #define DLL_EXPORTS extern"C"_declspec(dllimport) #endif //函数声明 DLL_EXPORTS int Add(int a,int b); DLL_EXPORTS int Sub(int a,int b); DLL_EXPORTS int Divide(int a,int b); #endif//DLLTEST_H

测试代码:

typedefint(*Add)(int a, int b); typedefint(*Sub)(int a, int b); HINSTANCE hDLL; Add Add_;//函数指针 hDLL =LoadLibrary(_T("D:/DLLTest.dll"));//加载动态链接库DLLTest.dll文件; Add_ = (Add)GetProcAddress(hDLL,"Add"); intresult = Add_(5, 8); printf("5+8:%d\n",result); FreeLibrary(hDLL);//卸载.dll文件;

以下是采用__declspec(dllexport)方式导出,不推荐这种方式需要注意函数名的书写问题! 现在DLLTest.h中有函数(采用__declspec(dllexport)方式导出)

3.2 示例2:_declspec(dllexport) #ifndef DLLTEST_H #define DLLTEST_H //该宏完成在dll项目内部使用__declspec(dllexport)导出 //在dll项目外部使用时,用__declspec(dllimport)导入 //宏DLL_EXPORTS在.cpp中定义 #ifdef DLL_EXPORTS #define DLL_EXPORTS __declspec(dllexport) #else #define DLL_EXPORTS __declspec(dllimport) #endif int DLL_EXPORTS Add(int a,int b); int DLL_EXPORTS Sub(int a,int b); int DLL_EXPORTS Divide(int a,int b); #endif//DLLTEST_H

测试代码:

typedefint(*Add)(int a, int b); typedefint(*Sub)(int a, int b); HINSTANCE hDLL; Add Add_;//函数指针 //也可以采用hDLL =LoadLibrary(_T("D:/DLLTest.dll")); hDLL =LoadLibraryA(("D:/DLLTest.dll"));//加载动态链接库DLLTest.dll文件; Add_ = (Add)GetProcAddress(hDLL,"?Add@@YAHHH@Z");//!!!!获取函数地址 intresult = Add_(5, 8); printf("5+8:%d\n",result); FreeLibrary(hDLL);//卸载.dll文件;

这里需要注意的是:GetProcAddress(hDLL,“函数名”);中的函数名要是DLL中的函数名,这个函数名可以用PE Explorer软件查看 由于采用的是VC++处理函数名方式,所以 GetProcAddress(hDLL,"?Add@@YAHHH@Z");// GetProcAddress(hDLL,“函数名”); 在这里插入图片描述

而不是简单的“Add”,因为DLL中的函数名是结果VC++方式处理过的函数名 显示调用,最好采用extern “C”的方式导出DLL 在这里插入图片描述 所以采用隐式链接方式的时候,只加载需要的DLL,在附加依赖项中,只添加需要的DLL对应的lib,不要多加,否则会造成1.加大程序启动时间 2.内存浪费

参考文献

1、《C++ Primer》(第4版特别版) 2、《VC++深入详解》孙鑫

原文链接:动态链接库dll的两种加载方式



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3