DLL动态链接库和LIB静态链接库

上传人:飞*** 文档编号:39974177 上传时间:2018-05-21 格式:DOCX 页数:5 大小:19.72KB
返回 下载 相关 举报
DLL动态链接库和LIB静态链接库_第1页
第1页 / 共5页
DLL动态链接库和LIB静态链接库_第2页
第2页 / 共5页
DLL动态链接库和LIB静态链接库_第3页
第3页 / 共5页
DLL动态链接库和LIB静态链接库_第4页
第4页 / 共5页
DLL动态链接库和LIB静态链接库_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《DLL动态链接库和LIB静态链接库》由会员分享,可在线阅读,更多相关《DLL动态链接库和LIB静态链接库(5页珍藏版)》请在金锄头文库上搜索。

1、1:神马是:神马是 Dll 和和 Lib,神马是静态链接和动态链接,神马是静态链接和动态链接 大家都懂的,DLL 就是动态链接库,LIB 是静态链接库。DLL 其实就是 EXE,只不过没 main。 动态链接是相对于静态链接而言的。所谓静态链接就是把函数或过程直接链接到可执 行文件中,成为可执行程序中的一部分,当多个程序调用同样的函数时,内存里就会有这 个函数的多个拷贝,浪费内存资源。而动态链接则是提供了一个函数的描述信息给可执行 文件(并没有内存拷贝) ,当程序被夹在到内存里开始运行的时候,系统会在底层创建 DLL 和应用程序之间的连接关系,当执行期间需要调用 DLL 函数时,系统才会真正根

2、据链接的 定位信息去执行 DLL 中的函数代码。 在 WINDOWS32 系统底下,每个进程有自己的 32 位的线性地址空间,若一个 DLL 被进 程使用,则该 DLL 首先会被调入 WIN32 系统的全局堆栈,然后通过内存映射文件方式映射 到这个 DLL 的进程地址空间。若一个 DLL 被多个进程调用,则每个进程都会接收到该 DLL 的一个映像,而非多份的拷贝。但,在 WIN16 系统下,每个进程需要拥有自己的一份 DLL 空间,可以理解为何静态链接没啥区别。2:DLL 和和 LIB 区别和联系。区别和联系。 DLL 是程序在运行阶段才需要的文件。 LIB 是程序编译时需要链接的文件。 DL

3、L 只有一种,其中一定是函数和过程的实现。 LIB 是有两种。若只生成 LIB 的话,则这个 LIB 是静态编译出来的,它内部包含了函数 索引以及实现,这个 LIB 会比较大。若生成 DLL 的话,则也会生成一个 LIB,这个 LIB 和刚 才那个 LIB 不同,它是只有函数索引,没有实现的,它很小。但是这俩 LIB 依然遵循上个原 则,是在编译时候是需要被链接的。若不链接第一个 LIB 的话,在程序运行时会无法找到 函数实现,当掉。若不链接第二个 LIB 的话,在程序运行时依然会无法找到函数实现。但 第二种 LIB 有一种替代方式,就是在程序里,使用 LoadLibrary,GetProcA

4、ddress 替代第二个 LIB 的功能。第一种 LIB 生成的 EXE 文件会很大,因为 LIB 所有信息被静态链接进 EXE 里了。 第二种 LIB 生成的 EXE 文件会比较小,因为函数过程实现依旧在 DLL 内。 我们可以将静态编译的 LIB 称为 静态链接库。但动态编译的 LIB 称为 引入库。可能会 比较好一些。 静态链接 LIB 的优点是免除挂接动态链接库,缺点是 EXE 大,版本控制麻烦些。 动态链接 DLL 的优点是文件小,版本更换时换 DLL 就好了,缺点是多了点文件。动态 链接若是被多个进程使用,会更加方便和节省内存。3:为什么编译:为什么编译 DLL 时总会同时生成一个

5、时总会同时生成一个 LIB?这个?这个 LIB 有用吗?有用吗? 若我们不是用静态链接,而使用 DLL,那么我们也需要一个 LIB,这个 LIB 的作用是被 链接到程序里,在程序运行时告诉系统你需要什么 DLL 文件。这个 LIB 里保存的是 DLL 的 名字和输出函数入口的顺序表。它是有意义的。 当然,若我们的应用程序里不链接这个 LIB,则可以使用 LoadLibrary,GetProcAddress 来 告诉系统我们在运行时需要怎么着 DLL 以及其内的函数。4:DLL 意义。意义。 1:DLL 真正实现了跨语言。各种语言都可以生成 DLL,而对系统以及应用程序来说, 哪种语言生成的 D

6、LL 是没有区别的。 2:DLL 有足够的封装性,对于版本更新有很大好处。因为 DLL 是运行期间才会使用, 所以,即使 DLL 内函数实现有变化(只要参数和返回值不发生变化) ,程序是不需要进行编 译的。大大提高了软件开发和维护的效率。 3:DLL 被多个进程使用,因为有内存映射机制,无需占用更多内存。5:创建:创建 DLL。 (注意:某志就不再讲解使用 MFC AppWizarddll 方式创建 DLL 了。有兴趣的自己去百度。 这里创建 DLL 只指使用 Win32 Dynamic-link Library 创建 Non-MFC DLL。 , 每个应用程序必须有一个 main 或者 wi

7、nmain 函数作为入口,DLL 一样,有自己的缺省 的入口函数,就是 DllMain。函数如下 BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) switch (ul_reason_for_call)case DLL_PROCESS_ATTACH: / 进程被调用case DLL_THREAD_ATTACH: / 线程被调用case DLL_THREAD_DETACH: / 线程被停止case DLL_PROCESS_DETACH: / 进程被停止break;return

8、TRUE; 一般情况下,我们不需要对这个缺省的入口函数进行什么修改,它就会使动态链接库 得到正确的初始化。但是,当我们的 DLL 需要额外分配内存或者资源的时候,或者,DLL 希望对调用自己的进程或线程进行初始化或清除的额外操作时,可以在上述代码 case 中加 一些自己感冒的东东。 (懒不想细写了- -Orz,现在是晚上 2 点了,明天还一堆的事情) DLL 对于导出类和导出函数没啥不同。只要加上 _declspec( dllexport ) 修饰函数或者类就 好了。 但是有查看过 DLL 代码的人员都会经常见到这么一段代码 #ifdef FK_DLL_EXPORTS #define FK_

9、DLL _declspec( dllexport ) #else #define FK_DLL _declspec( dllimport ) #endif意义很明显,但是,问题是 FK_DLL_EXPORTS 这个宏是应该在哪儿定义呢?在 DLL 项 目内,还是在使用 DLL 的应用程序内? export 是导出。import 是导入。对于 DLL 来说,是要导出这些函数给其他应用程序使 用的,所以应当定义 FK_DLL_EXPORTS 宏。对于使用 DLL 的应用程序来说,是导入,是无 需定义的。 使用时候也很简单。 class FK_DLL CMyDllClass ;则整个类被导出。 FK

10、_DLL void MyTestFun( int a );则该函数被导出。 但是有时我们可以见到这样的代码 extern “C“ FK_DLL void MyTestFun2( float b );其中 extern “C“的原理就是标示该函数要求以 C 形式去进行编译,不要以 C+形式去编 译。具体的编译原理就不罗嗦了,简而言之,被 extern “C“定义函数,可以被 C 以及其他语言进行 DLL 调用,而未被 extern “C“定义的函数,C 是无法访问 DLL 中这个函数的。在 VS 中开发 DLL 还有一种方式,使用.def 文件。 新建个文本文档,改后缀为 FKDll.def,加

11、入到工程里。 FKDll.def 里加入以下代码 LIBRARY FKDll EXPORTS MyTestFun1 MyTestFun22就可以了。其中,LIBRARY 语句是说明.def 文件是属于 FKDll 这个 Dll 的。EXPORTS 下面 是我们需要导出的函数名。后面加的+数字,是表示导出函数的顺序编号。这样就足够了。6:使用:使用 DLL 使用 DLL 有两种方式。显式链接和隐式链接。 隐式链接很容易。直接#progam comment(lib, “FKDll.lib“) 就可以。当然,也可以在项目 工程-属性-链接库里加上库和路径(相对路径和绝对路径都可以) 。 显式链接则麻

12、烦些。在程序中使用 LoadLibrary 加载 DLL,再 GetProcAddress 获取函数 实现,在程序退出之前,调用 FreeLibrary 来动态释放掉链接库。 例如: void Main() typedef void (*FKDllFun1)(int a);FKDllFun1 pFun1;HINSTANCE hDLL = LoadLibrary(“FKDll.dll“); / 若 hDll 为空则读取 Dll 失败。pFun1 = (pFun1)GetProcAddress(hDll, “MyTestFun1“ ); / 从应用程序中的 DLL 镜像中获取 名为 MyTestF

13、un1 的函数指针pFun1( 100 );FreeLibrary(hDll); 当然,我们刚才.def 里面还指定了导出函数的导出顺序,那么我们可以修改里面获取 函数指针那一段为 pFun1 = (pFun1)GetProcAddress(hDll, MAKEINTERSOURCE(1) ); / 1 是刚才指定的 MyTestFun1 函数导出顺序编号。 7:比较显式链接和隐式链接。:比较显式链接和隐式链接。 可能的话,尽量使用显式链接。 显式链接可以在程序执行时动态的加载 DLL 和卸载 DLL 文件,隐式链接是做不到的。 显式链接 LoadLibrary,GetProcAddress

14、时能获知是否加载失败,我们可以对其进行检 查错误处理。而显式链接可能是一个很恶劣的提示或是程序崩溃的结果。 对于有些 Ex 类型的加强函数,显式链接可以允许我们找到替代方案。也包括选择 D3d9.dll 和 OpenGL.dll 时也可采用同样处理。 例如: if( GetProcAddress( hDll, “FKDllFunEx“) = NULL ) pFun = GetProcAddress( hDll, “FKDllFun“); / 然后使用 pFun 进行处理8:导出类和导出函数:导出类和导出函数 类和函数的导出方式上面给出了说明,原本极其类似的。 我们说下使用导出类。 若我们隐式的

15、使用了一个导出类,则我们在应用程序里继承它的时候,就如同该类就 在应用程序代码里一样,无需任何处理。 例如: class FK_DLL CMyDllClass ; / Dll 文件内的代码 -class CAppClass : public CMyDllClass / 应用程序内代码,无需做任何处理。 . 也可以直接使用 DLL 导出类 void main CMyDllClass* pClass = new CMyDllClass (); 但是,若应用程序声明或者分类一个 DLL 中导出类的对象时会存在一个很讨厌的问题: 这个操作会使内存跟踪系统失效,使其错误的报告内存分配和释放情况。 为解决

16、这个问题,我们可以给出两个接口函数对 DLL 导出类进行创建销毁支持,就可 以使内存跟踪系统正常了。例如 class FK_DLL CMyDllClass ; 额外增加俩函数 FK_DLL CMyDllClass* CreateMyDllClass() return new CMyDllClass(); FK_DLL void DestoryMyDllClass( CMyDllClass* p_pClass ) delete p_pClass; 上面的方法可以正确进行内存跟踪了,但是,因为 DLL 导出类 CMyDllClass 依旧是导出 的状态,用户同样可以跳过我们提供的接口直接使用。那么怎么办呢。方法是不再对类进 行 DLL 导出,而对类内的函数全部进行 DLL 导出即可, 但是若仅仅提供上面两个接口函数以及类内全部函数,的确功能可以实现,却无法进 行类继承了。若这个类继

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号