DLL动态库相关问题解析
来源:互联网 发布:美女网络主播 编辑:程序博客网 时间:2024/06/04 23:52
动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。
动态链接与静态链接的不同之处在于:动态链接允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。
使用动态链接代替静态链接有若干优点。DLL 节省内存,减少交换操作,节省磁盘空间,更易于升级,提供售后支持,提供扩展 MFC 库类的机制,支持多语言程序,并使国际版本的创建轻松完成。
一、动态库后缀名有限制吗?
没有限制,任意的后缀都可作为动态库的后缀名。Dll后缀无所谓,但是保持下图所示一致可以消除编译时提示后缀名不一致警告问题。
二、动态库编译、链接、生成都需要哪些文件
下图所示即动态库编译、链接、生成都需要的文件:
三、导入导出方式有哪些?
隐式链接:
为隐式链接到 DLL,可执行文件必须从 DLL 的提供程序获取下列各项:
- 包含导出函数和/或 C++ 类的声明的头文件(.h 文件),类、函数和数据均应具有 __declspec(dllimport)。
- 要链接的导入库(.LIB files)(生成 DLL 时链接器创建导入库)。
- 实际的 DLL(.dll 文件)。
- 使用 DLL 的可执行文件必须包括头文件,此头文件包含每个源文件中的导出函数(或 C++ 类),而这些源文件包含对导出函数的调用。从编码的角度讲,导出函数的函数调用与任何其他函数调用一样。
- 若要生成调用可执行文件,必须与导入库链接。如果使用的是外部生成文件,请指定导入库的文件名,此导入库中列出了要链接到的其他对象 (.obj) 文件或库。
- 操作系统在加载调用可执行文件时,必须能够定位 DLL 文件。 Dll 导出的方式可以是 导出的方式可以是 导出的方式可以是 导出的方式可以是__declspec(dllexport),也可以是在.def文件中
导入 DLL进行编译的时候 ,可以使用 __declspec(dllimport) 指定导入声明和#pragma comment(lib, "MyDllAPI.lib")指定库文件导入,或者仅使用__declspec(dllimport)指定声明,下图配置指定lib导入。
显式链接:
在显式链接下,应用程序必须进行函数调用以在运行时显式加载 DLL。为显式链接到 DLL,应用程序必须:
- 调用 LoadLibrary(或相似的函数)以加载 DLL 和获取模块句柄。
- 调用 GetProcAddress,以获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
- 使用完 DLL 后调用 FreeLibrary。
函数FunC也可以这样调用:
利用ordinal值(def文件中导出函数后面的@N)进行调用,但使用 GetProcAddress Function 时,有以下几点需要特别留意:
1. 第二个参数类型是 LPCSTR,不是 LPCTSTR;
2. 用 __declspec(dllexport),按C 名称修饰(extern "C") 导出的函数名,对于 __stdcall 和 __fastcall 调用约定是相同的;对 __cdecl 是不同的(导出的函数名没有前面的下划线);
3. 即使返回值不是 NULL,也有可能发生错误。当 .def 模块不是连续地从 1 开始编号 ordinal 值,那么,如果用一个无函数对应的 ordinal 值调用 GetProcAddress,就会发生错误,返回一个无效的非 NULL 地址;
4. 最好用函数名,而不是 ordinal 值调用 GetProcAddress,以避免不同版本 Dll 中某些函数不存在的情况。
注:确认 Dll 的导出函数名,可以用 DUMPBIN /EXPORTS dll_file_name.dll 命令,然后查看name 列。
5. MAKEINTRESOURCE宏定义如下:
如果由于UNICODE导致使用MAKEINTRESOURCEW将INT转换为了LPWSTR,那么直接使用MAKEINTRESOURCEA即可。即
不要拘泥于现有的宏定义。
四、导入导出代码实现:
利用预编译器预先定义一个宏,作为条件语句实现导入导出在客户端和本地实现不同声明
五、def文件改名称问题
如下图所示保持一致即可。
六、 纯资源DLL定义
需要关闭入口,如下图所示:
七、EXPORTS关键字
引入了一个由一个或多个 definitions(导出的函数或数据)组成的节。每个定义必须在单独一行上。
EXPORTS 关键字可以在第一个定义所在的同一行或前一行上。.def 文件可以包含一个或多个 EXPORTS 语句。
导出 definitions 的语法为:
entryname 是要导出的函数名或变量名。这是必选项。如果导出的名称与 DLL 中的名称不同,则通过internalname指定 DLL 中导出的名称。例如,如果 DLL 导出函数 func1(),要将它用作 func2(),则应指定:
@ordinal 允许指定是序号而不是函数名将进入 DLL 的导出表。这有助于最小化 DLL 的大小。.LIB 文件将包含序号与函数之间的映射,这使您得以像通常在使用 DLL 的项目中那样使用函数名。
可选的 NONAME 关键字允许只按序号导出,并减小结果 DLL 中导出表的大小。但是,如果要在 DLL 上使用 GetProcAddress,则必须知道序号,因为名称将无效。
可选的 PRIVATE 关键字禁止将 entryname 放到由 LINK 生成的导入库中。它对同样是由 LINK 生成的图像中的导出无效。
可选的 DATA 关键字指定导出的是数据,而不是代码。例如,可以导出数据变量,如下所示:
当对同一导出使用 PRIVATE 和 DATA 时,PRIVATE 必须位于 DATA 的前面。
有三种导出定义的方法,按照建议的使用顺序依次为:1.源代码中的__declspec(dllexport) 关键字
2..def 文件中的 EXPORTS 语句
3.LINK 命令中的/EXPORT 规范
所有这三种方法可以用在同一个程序中。LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。
以下是 EXPORTS 节的示例:
注意,使用 .def 文件从 DLL 中导出变量时,不需要在变量上指定 __declspec(dllexport)。但是,在任何使用 DLL 的文件中,仍必须在数据声明上使用 __declspec(dllimport)。
八、后缀的问题
默认.dll后缀的动态库,显式链接时可以只要名称,但是改过后缀的动态库则要全称,包括后缀。
九、 Depends查看DLL
在.def文件中导出的函数是c方式的声明,__declspec(dllexport)导出的是c++形式的函数声明。
- DLL动态库相关问题解析
- 动态链接库dll和log4cpp的相关问题
- dll动态库调用问题
- 动态链接库(dll)文件解析
- win7 无法定位序数5076于动态链接库mfc42d.dll上问题解析
- C#Dll 相关问题
- dll 动态库文件的一些问题
- 动态链接库DLL引入问题
- 移动项目中JAVA与C/C++编解码相关的JNI动态库问题(.dll vs .so)
- 动态调用dll问题
- 白话完全解析动态规划原理及相关问题(一)
- 白话完全解析动态规划原理及相关问题(二)
- DLL内存分配相关问题
- NGINX加载动态库相关问题
- VS2010生成动态库相关问题
- 动态数据源相关问题
- pytest相关问题解析
- CString导致使用Dll动态库无法编译的问题
- jquery得到子孙节点变通方法
- POJ 3280 Cheapest Palindrome
- 从三大互联网巨头布局,看移动时代的商业逻辑
- 对九个超级程序员的采访
- 【Record 1】什么是user story?
- DLL动态库相关问题解析
- struts2中ognl表达式的运用
- NYOJ 题目485 A*B Problem
- Makefile的静态模式
- 在Mac OS X中配置Apache + PHP + MySQL
- 远程 DEBUG tomcat
- 你可能不知道的Shell
- 28个Unix/Linux的命令行神器
- POJ 1113 Wall 凸包求周长