动态链接库详解

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

lib和dll的联系首先我们来明白一个工程从创建到可执行文件的过程:创建工程——编写代码——编译——链接——可执行文件。下一篇日记中会重点介绍VC的编译与链接的过程,此文重点在讲项目、dll与lib。我相信任何人肯定能从VC6.0的目录下找到两个文件夹lib与include。而include内的都是大家熟悉的头文件(如iostream.h、conio.h)等文件。这些头文大家都是能够查看与打开的,就好比你写的头文件一样,里面有很多的声明。而且我敢肯定的是大家肯定找不到的是.cpp文件。你也许会好奇光有头文件里这些类这些声明,而没有具体的实现的话(c++一般都是在.h中写类的一些接口,而实现的部分是在.cpp文件中),我们是如何来用它的呢?这就和你的编译器有很大的关系了。不同的编译器处理的方式不通。就拿VC6.0来说:假设你有3个.cpp文件(a.cpp、b.cpp、c.pp)。在编译器预处理的时候它会把头文件(.h)的内容都会插入到你的对应的.cpp文件中。如a.cpp文件中有#includeiostream、#includea.h。则预处理的时候会把a.h文件的内容都复制到了a.cpp文件中,当然还有include文件夹下的iostream.h内容,当然iostream.h文件中的ios.h,streamb.h,istream.h,ostream.h中的内容也会通过递归的方式加入进来(当然不是都不是整个.h文件的内容都一定要加入进去的,预处理做的事情不只有这么简单,如想了解可以去查资料,这里只是不必增加复杂度,你暂时可以理解为都加入进去了)。然后每个.cpp文件其实可以理解为一个编译的单元,可以分别编译的。(这样的做法,很明显可以提高速度,如果你每改一个文件,所以文件都要重新都编译下的话,所耗的时间是相当的惊人的,所以c++把每个编译单元都独立出来编译成obj文件,然后在通过链接成为一个可执行文件。)。通过编译每个cpp文件它会产生一个.obj文件。如上面的三个文件它会产生a.obj,b.obj,c.obj文件(还有一些其他文件,但你不需要了解,你需要记住只是这里说的是VC6.0的编译器)。这里面都是2进制的代码,每个obj文件它所含的内容除了编译后的产生的数据和代码外,它还必须含有3个表:未解决符号表、导出符号表、地址重定向表。先别着急了解这3个表的含义。我们来通过程序了解:假设有:A.cpp:externintm_a;//声明变量avoidset(){m_a=6;}B.cpp:intm_a=6;//全局变量avoidadd(){m_a++;};编译这两个文件产生了A.obj、B.obj文件。可这些文件是分别编译的,我们怎么知道A.cpp中的值的大小呢?这就是表的作用了!.obj内除了自己数据外,还有的导入符号表和未解决符号表就是告诉编译器我能提供什么东西,我还需要什么东西。地址重定向表是解决地址冲突的,这里不做深究。如:A.obj的导出符号表中有m_a、set()。未解决表中没有。B.obj的导出符号表中有add()。未解决表中有m_a;这样以后再链接的时候,编译器去找B.obj需要的m_a的时候找到了唯一的A.obj中导出的m_a。(下一章的内部连接和外部连接会更深入的了解)。这样然后整合到一个.exe(含main方法的那个cpp文件)文件中成为一个可执行文件。好了现在说完这些,你就会更加清楚的去了解lib与dll内。lib分为静态的链接库和动态的链接库,这些也都是2进制代码。(1)我们不是在VC的lib文件夹下看到了很多的lib文件吗?这些是静态的链接库,你其实可以把它理解为一个项目(项文件含有的obj文件的总和,如为完成某个功能,一般不是只需要一个cpp文件就能完成的,而每个cpp在编译后都会产生obj)的obj文件(为方便理解才这么所,当然不可能这么简单)。当然这些就是Microsoft的VC6.0的源文件发布后能提供的东西。所以我们自己编写的代码中的头文件需要的东西,可以对应的lib找到对应的入口。如iostream.h中的iostream(constiostream&)函数需要的东西可以从lib中找到入口,如果某个对应lib里的导出符号表提供了iostream(constiostream&)函数的入口,我们就调用这lib中的iostream(constiostream&)具体实现(lib里的2进制代码)。(2)而使用动态链接中的lib,不是obj文件的集合,即里面不会有实际的实现,它只是提供动态链接到dll(后面有说到它)所需要的信息,这种lib可以在编译一个dll工程时由编译器生成。所有你写的代码是结合了前人无数的研究与开发的产品,集合了几代人的成就。你好比是用到了他们所写的源码一样,只是你看不到它的源码(.cpp文件)而已。按照我家GY的话来说就是一代一代哟!(3)dll是动态链接库。区分动态的链接库与静态的链接库很简单,就是静态的链接库是在程序链接的时候就已经链接到exe文件(可执行文件)内了!而动态的链接库是你的exe(可执行文件)运行的时候需要的链接库。也就是说如果你用到了dll的话,那你光有个exe文件没用,想要运行的话必须还要有动态链接库的存在,如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。如果有dll文件(这就是VS2008的内库了,好比就是C++提供的那些lib一样,它这么做的目的还是为了节省了内存资源,提高时间,后面有说到),那么lib一般是一些索引信息,记录了dll中函数的入口和位置,dll中是函数的具体内容;如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。使用静态编译的lib文件,在运行程序时不需要再挂动态库,缺点是导致应用程序比较大,而且失去了动态库的灵活性,发布新版本时要发布新的应用程序才行。动态链接的情况下,有两个文件:一个是lib文件,一个是dll文件。lib包含被dll导出的函数名称和位置,dll包含实际的函数和数据,应用程序使用lib文件链接到dll文件。在应用程序的可执行文件中,lib中存放的不是被调用的函数代码,而是dll中相应函数代码的地址,从而节省了内存资源。(4)总之1个静态的lib可以看成是若干个obj的内容(vc6.0安装包的内容)。而动态的lib一般是和dll一起存在的,这时候的lib中存放的不是被调用的函数代码,而是dll中相应函数代码的地址,而dll是只能在程序运行的时候才能使用的(VS2008的内容)。API函数与dll文件的关系API就是应用程序编程接口。它是能用来操作组件、应用程序或者操作系统的一组函数。典型的情况下,API由一个或多个提供某种特殊功能的dll组成。dll是一个文件,其中包含了在Microsoft®Windows®下运行的任何应用程序都可调用的函数。运行时,dll中的函数动态地链接到调用它的应用程序中。无论有多少应用程序调用dll中的某个函数,在磁盘上只有一个文件包含该函数,且只在它调入内存时才创建该dll。您听到最多的API可能是WindowsAPI,它包括构成Windows操作系统的各种dll。每个Windows应用程序都直接或间接地与WindowsAPI互动。WindowsAPI保证Windows下运行的所有应用程序的行为方式一致。注意随着Windows操作系统的发展,现已发布了几个版本的WindowsAPI。Windows3.1使用Win16API。Microsoft®WindowsNT®、Windows95和Windows98平台使用Microsoft®Win32®API。除WindowsAPI外,其他一些API也已发布。例如,邮件应用程序编程接口(MAPI)是一组可用于编写电子邮件应用程序的dll。API传统上是为开发Windows应用程序的C和C++程序员编写的,但其他的编程语言(包括VBA)也可以调用dll中的函数。因为大部分dll主要是为C和C++程序员编写和整理说明的,所以调用dll函数的方法与调用VBA函数会有所不同。在使用API时必须了解如何给dll函数传递参数。警告调用WindowsAPI和其他dll函数可能会给您的应用程序带来不良影响。从自己的代码中直接调用dll函数时,您绕过了VBA通常提供的一些安全机制。如果在定义或调用dll函数时出现错误(所有程序员都不可避免),可能会在应用程序中引起应用程序错误(也称为通用性保护错误,或GPF)。最好的解决办法是在运行代码以前保存该项目,并确保了解dll函数调用的原理。API是系统提供的函数,和语言无关,可以用C写,也可以用C++写,也可以用其他语言写。如何调用dll中的函数在dll工程中的cpp中函数定义如下:externC_declspec(dllexport)intadd(inta,charb){returna+b;}一、显式链接调用的dll的主工程的main文件中代码如下:#includestdio.h#includeWindows.h#includetchar.hintmain(){HMODULEhModule=NULL;typedefint(*Func)(inta,intb);//动态加载dll文件hModule=LoadLibrary(_TEXT(..//Debug//FuncDll.dll));//获取add函数地址FuncfAdd=(Func)GetProcAddress(hModule,add);//使用函数指针printf(%d/n,fAdd(5,2));//最后记得要释放指针FreeLibrary(hModule);return0;}二、隐式链接调用的dll的主工程的main文件中代码如下:#includestdio.h#includeWindows.h#includetchar.h//先把lib链接进来#pragmacomment(lib,..//Debug//FuncDll.lib)//外部声明的add函数externC_declspec(dllimport)intadd(inta,charb);intmain(){//直接调用add函数printf(%d/n,add(5,2));return0;}写一个简单的dll文件首先建立一个dll类型的工程,然后创建一个cpp文件,内容如下:externC__declspec(dllexport)intadd(inta,intb)//需要注意的是,这个declspec前面是2个下划线{return(a+b);}externC__declspec(dllexport)intsub(inta,intb){return(a-b);}编译之后,会在debug中生成dll,lib等文件。在工程中再添加一个测试项目,项目中的cpp文件内容为:#includeiostreamusingnamespacestd;externC__declspec(dllexport)intadd(inta,intb);externC__declspec(dllexport)intsub(inta,intb);int_tmain(intargc,_TCHAR*argv[]){return0;}最后,就是在项目属性中-链接器-命令行中-添加MyDll.lib文件(所谓隐式链接)再运行test工程,运行成功。

1 / 5
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功