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

上传人:小** 文档编号:111496552 上传时间:2022-06-20 格式:DOC 页数:5 大小:60KB
收藏 版权申诉 举报 下载
DLL动态链接库和LIB静态链接库_第1页
第1页 / 共5页
DLL动态链接库和LIB静态链接库_第2页
第2页 / 共5页
DLL动态链接库和LIB静态链接库_第3页
第3页 / 共5页
资源描述:

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

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

2、个进程有自己的32位的线性地址空间,若一个DLL被进程使用,则该DLL首先会被调入WIN32系统的全局堆栈,然后通过内存映射文件方式映射到这个DLL的进程地址空间。若一个DLL被多个进程调用,则每个进程都会接收到该DLL的一个映像,而非多份的拷贝。但,在WIN16系统下,每个进程需要拥有自己的一份DLL空间,可以理解为何静态链接没啥区别。2:DLL和LIB区别和联系。DLL是程序在运行阶段才需要的文件。LIB是程序编译时需要链接的文件。DLL只有一种,其中一定是函数和过程的实现。LIB是有两种。若只生成LIB的话,贝这个LIB是静态编译出来的,它内部包含了函数索引以及实现,这个LIB会比较大。

3、若生成DLL的话,则也会生成一个LIB,这个LIB和刚才那个LIB不同,它是只有函数索引,没有实现的,它很小。但是这俩LIB依然遵循上个原则,是在编译时候是需要被链接的。若不链接第一个LIB的话,在程序运行时会无法找到函数实现,当掉。若不链接第二个LIB的话,在程序运行时依然会无法找到函数实现。但第二种LIB有一种替代方式,就是在程序里,使用LoadLibrary,GetProcAddress替代第二个LIB的功能。第一种LIB生成的EXE文件会很大,因为LIB所有信息被静态链接进EXE里了。第二种LIB生成的EXE文件会比较小,因为函数过程实现依旧在DLL内。我们可以将静态编译的LIB称为静

4、态链接库。但动态编译的LIB称为引入库。可能会比较好一些。静态链接LIB的优点是免除挂接动态链接库,缺点是EXE大,版本控制麻烦些。动态链接DLL的优点是文件小,版本更换时换DLL就好了,缺点是多了点文件。动态链接若是被多个进程使用,会更加方便和节省内存。3:为什么编译DLL时总会同时生成一个LIB?这个LIB有用吗?若我们不是用静态链接,而使用DLL,那么我们也需要一个LIB,这个LIB的作用是被链接到程序里,在程序运行时告诉系统你需要什么DLL文件。这个LIB里保存的是DLL的名字和输出函数入口的顺序表。它是有意义的。当然,若我们的应用程序里不链接这个LIB,则可以使用LoadLibrar

5、y,GetProcAddress来告诉系统我们在运行时需要怎么着DLL以及其内的函数。4:DLL意义。1:DLL真正实现了跨语言。各种语言都可以生成DLL,而对系统以及应用程序来说,哪种语言生成的DLL是没有区别的。2:DLL有足够的封装性,对于版本更新有很大好处。因为DLL是运行期间才会使用,所以,即使DLL内函数实现有变化(只要参数和返回值不发生变化),程序是不需要进行编译的。大大提高了软件开发和维护的效率。3:DLL被多个进程使用,因为有内存映射机制,无需占用更多内存。5:创建DLL。(注意:某志就不再讲解使用MFCAppWizarddll方式创建DLL了。有兴趣的自己去百度。这里创建D

6、LL只指使用Win32Dynamic-linkLibrary创建Non-MFCDLL。,每个应用程序必须有一个main或者winmain函数作为入口,DLL样,有自己的缺省的入口函数,就是DIIMain。函数如下BOOLAPIENTRYDllMain(HMODULEhModule,DWORDul_reason_for_call,LPVOIDlpReserved)switch(uI_reason_for_caII)caseDLL_PROCESS_ATTACH:/进程被调用caseDLL_THREAD_ATTACH:/线程被调用caseDLL_THREAD_DETACH:/线程被停止caseDLL

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

8、fineFK_DLL_decIspec(dIIexport)#eIse#defineFK_DLL_decIspec(dIIimport)#endif意义很明显,但是,问题是FK_DLL_EXPORTS这个宏是应该在哪儿定义呢?在DLL项目内,还是在使用DLL的应用程序内?export是导出。import是导入。对于DLL来说,是要导出这些函数给其他应用程序使用的,所以应当定义FK_DLL_EXPORTS宏。对于使用DLL的应用程序来说,是导入,是无需定义的。使用时候也很简单。cIassFK_DLLCMyDIICIass;则整个类被导出。FK_DLLvoidMyTestFun(inta);则该函

9、数被导出。但是有时我们可以见到这样的代码externCFK_DLLvoidMyTestFun2(fIoatb);其中externC的原理就是标示该函数要求以C形式去进行编译,不要以C+形式去编译。具体的编译原理就不罗嗦了,简而言之,被externC定义函数,可以被C以及其他语言进行DLL调用,而未被externC定义的函数,C是无法访问DLL中这个函数的。在VS中开发DLL还有一种方式,使用.def文件。新建个文本文档,改后缀为FKDll.def,加入到工程里。FKDll.def里加入以下代码LIBRARYFKDllEXPORTSMyTestFun1MyTestFun22就可以了。其中,LIB

10、RARY语句是说明.def文件是属于FKDll这个Dll的。EXPORTS下面是我们需要导出的函数名。后面加的+数字,是表示导出函数的顺序编号。这样就足够了。6:使用DLL使用DLL有两种方式。显式链接和隐式链接。隐式链接很容易。直接#progamcomment(lib,FKDll.lib)就可以。当然,也可以在项目工程-属性-链接库里加上库和路径(相对路径和绝对路径都可以)。显式链接则麻烦些。在程序中使用LoadLibrary加载DLL,再GetProcAddress获取函数实现,在程序退出之前,调用FreeLibrary来动态释放掉链接库。例如:voidMain()typedefvoid(

11、*FKDllFun1)(inta);FKDllFun1pFun1;HINSTANCEhDLL=LoadLibrary(FKDll.dll);/若hDll为空则读取Dll失败。pFun1=(pFun1)GetProcAddress(hDll,MyTestFun1);/从应用程序中的DLL镜像中获取名为MyTestFun1的函数指针pFun1(100);FreeLibrary(hDll);当然,我们刚才.def里面还指定了导出函数的导出顺序,那么我们可以修改里面获取函数指针那一段为pFun1=(pFun1)GetProcAddress(hDll,MAKEINTERSOURCE(1);/1是刚才指定

12、的MyTestFun1函数导出顺序编号。7:比较显式链接和隐式链接。可能的话,尽量使用显式链接。显式链接可以在程序执行时动态的加载DLL和卸载DLL文件,隐式链接是做不到的。显式链接LoadLibrary,GetProcAddress时能获知是否加载失败,我们可以对其进行检查错误处理。而显式链接可能是一个很恶劣的提示或是程序崩溃的结果。对于有些Ex类型的加强函数,显式链接可以允许我们找到替代方案。也包括选择D3d9.dll和OpenGL.dll时也可采用同样处理。例如:if(GetProcAddress(hDll,FKDllFunEx)=NULL)pFun=GetProcAddress(hDl

13、l,FKDllFun);/然后使用pFun进行处理8:导出类和导出函数类和函数的导出方式上面给出了说明,原本极其类似的。我们说下使用导出类。若我们隐式的使用了一个导出类,则我们在应用程序里继承它的时候,就如同该类就在应用程序代码里一样,无需任何处理。例如:classFK_DLLCMyDIICIass;/Dll文件内的代码classCAppClass:publicCMyDllClass/应用程序内代码,无需做任何处理。也可以直接使用DLL导出类voidmainCMyDIICIass*pCIass=newCMyDIICIass();但是,若应用程序声明或者分类一个DLL中导出类的对象时会存在一个很

14、讨厌的问题:这个操作会使内存跟踪系统失效,使其错误的报告内存分配和释放情况。为解决这个问题,我们可以给出两个接口函数对DLL导出类进行创建销毁支持,就可以使内存跟踪系统正常了。例如cIassFK_DLLCMyDIICIass;额外增加俩函数FK_DLLCMyDIICIass*CreateMyDIICIass()returnnewCMyDIICIass();FK_DLLvoidDestoryMyDIICIass(CMyDIICIass*p_pCIass)deIetep_pCIass;上面的方法可以正确进行内存跟踪了,但是,因为DLL导出类CMyDIICIass依旧是导出的状态,用户同样可以跳过我

15、们提供的接口直接使用。那么怎么办呢。方法是不再对类进行DLL导出,而对类内的函数全部进行DLL导出即可,但是若仅仅提供上面两个接口函数以及类内全部函数,的确功能可以实现,却无法进行类继承了。若这个类继承很重要,必须开放,那么就需要使用新的内存跟踪程序替换应用程序内的原有内存跟踪程序。或者使用下面的一个方法。(见模块9:复杂问题)同样,我们也可以发现,在不导出DLL类本身,而只导出DLL类内函数也有一些好处,一些我们不希望外界知道的函数可以不设置导出标记,这进一步保护了DLL内函数的安全性。9:复杂问题。若我们使用LoadLibrary显式加载一个DLL,并尝试在应用程序中调用一个类内成员函数的

16、话,无论该函数是否在头文件中有声明,VS会给出一个unresolvedexternalsymbol(未解析的外部符号)的错误。我们此时可以将项目属性中的内联函数扩展选项修改为Only_inline或AnySuitable即可。但,我们可能在调试连编的时候期望关闭内联函数扩展,那么另一种解决方案是,将希望导出的函数声明为虚函数,例如classCMyDllClassFK_DLLvirtualvoidMyTestFun(inta)dosth();/用上面代码替换FK_DLLvoidMyTestFun(inta)dosth();这样做还有一个额外的好处。将导出的类成员函数设置为虚函数之后,该虚函数所在的类在应用程序中也如同被声明一样,可以接受继承。例如若是上面的做法,应用程序就可以进行顺利继承,而不必要求CMyDllClass被标示为导出。(原理不知,希望精通底层的高手协助解释。)classCAppClass:publicCMyDllClass/应用程序内代码,无需做任何处理。

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!