用了些时间学习了下LIB和DLL的一些知识,看了很多人的文章,也自己总结了一些,出于自己的理解...
1、LIB与DLL文件的区别
2、静态编译和动态链接的23事...
3、*.h、*.lib/*.a、*.dll 之间的关系
4、为无LIB的DLL制作LIB函数符号输入库
5、调用dll文件 <这里分C版接口和C++版接口,要弄清概念>
6、DEV-C++编写dll文件的几个知识点
1、DLL是一个完整的程序,中文名称为“动态链接库”,DLL中包含的主要有三块内容:1.全部变量 2.函数接口 3.资源。我们这里说的DLL中包含许多的函数接口,以便供我们来调用,实现我们的软件功能。DLL中有一个函数导出表,其中每一项都是一个函数名称,我们可以通过一定的方式连接这些函数接口,来调用这些函数的功能。DLL中的代码在程序主动调用的时候才会被调入内存(DLL没有自己的内存,它会被分配到调用程序的内存区域中)。
LIB被称为导入库文件,其中存放的内容根据动态和静态的区别会有两种不同的内容:
1、 在静态库情况下,函数和数据被编译成一个二进制文件(*.LIB),编译器在处理程序代码时,将从静态库中恢复这些函数和数据,并把他们和应用程序中的其他模块组合在一起生成可执行文件,(通俗的说就是,*.LIB文件会被整个编译进可执行文件中),因此发布的时候,就无需发布整个静态库文件,应用程序只有一个单独的exe文件比较干净,但是exe文件可能要大很多。
2 、 在动态库情况下,有连个文件,一个因入库(*.LIB)一个是DLL文件,此时LIB文件中包含的就不是实际的函数和数据了,而是被DLL文件中导出表中所有导出函数的名称和位置,因此整个LIB文件会很小,相比静态库的LIB文件(这个小的LIB文件在编译的时候还是会被编译进程序体内,因此这种情况发布的程序,也不用发布LIB文件,只需要DLL文件),DLL文件中才真正包含函数和数据,此时DLL文件中的函数和数据并不复制到程序中,程序中存放的则是DLL中所要调用的函数的内存地址,而不是被调用的函数代码。
2、其实在第一部分我已经将这块内容涉及到一些了,这里我通俗的说吧。
所谓静态编译就是,把你所需要的调用所有外部函数和数据编译成一个LIB文件,然后再把这个文件整个的融合到应用程序中,则这个可执行程序可谓集各方武功捆绑于一身,只有一个exe文件(发布的时候仅仅只需要这个文件就可以完成所有功能),单相对会比较大。
所谓动态编译就是,实现某些功能的代码分布在几个dll文件中,发布的时候你要将exe文件和这几个dll文件一起发布。Windows下的程序是最好的例子了,通常的程序只有一个单独的exe文件,其实很多实现某些功能的代码都在系统目录的几个dll文件中,需要的时候再去调用罢了。
3、这里我依然举例子来说明。假如现在我在做一个项目,我需要用到语音识别功能,我就去往某开发公司要,而他们为了盈利也只是给我了几个用来测试的文件,并且是已经编译好的文件,一种可能会给 my.h、my.lib 两个文件,一种可能会给 my.h、my.lib、my.dll 三个文件。具体的区别就是:第一种给两个文件的需要静态编译,也就是说my.lib会被融合到可执行程序中,发布的时候只有一个exe文件;第二种给三个文件的是需要动态链接,my.lib文件依然会和可执行程序融为一体,发布的时候需要将exe文件和dll文件一起发布。
这里还要说明一下 *.lib 和 *.a 文件,这两个文件都是导入库文件,VC++只能识别 *.lib文件,而DEV-C++ 这两种文件都可以识别使用。
4、依然举例子来理解,现在假设语音开发公司,只给了我这样两个文件 my.h 与 my.dll ,因为没有 my.lib 文件,那样我在调用其语音功能时会相当痛苦。这里先说说,假如说有 my.lib 文件会发生什么,在my.dll 中有一个add(int a,int b) 用于将两个数相加结果返回,那么在调用文件中,我仅仅只需要引入 my.h 头文件,然后就可以直接调用add()函数得到结果;但是如果没有my.lib文件,将十分的痛苦,我需要调用Win32 API 来实现,需要调用LoadLibrary()与GetProcAddress(), 大体如下面这样调用(这种方式成为显示,另外的一种是常用的隐式):
确实很痛苦吧,好了,罗嗦了这末多了,还没说假如说没有 *.lib 文件,那么如何从 dll 文件中导出来呢?这里我们需要两个工具,一个是微软提供的 dumpbin.exe(它依赖于另外两个文件:link.exe 与 mspdb60.dll ) 另一个是DEV-C++ 中的一个工具,叫 dlltool.exe。
dumpbin.exe可以从dll文件中导出一个 def 文件,注意这个文件只是个半成品,我们还需要手工改一下,后面会有讲解。
dlltool.exe 可以帮助我们用现有的 dll 和刚导出的 def 文件生成一个 .lib/.a 文件。
dumpbin的用法为: dumpbin /exports my.dll > my.def
dlltool的用法为: dlltool -D my.dll -d my.def -l my.lib //生成 .lib 文件
或者为: dlltool -D my.dll -d my.def -l my.a // 生成 .a 文件
经过这两步后就可以导出一个lib文件了。
接下来我们看一个用dumpbin.exe工具生成的def文件中的内容(def是一个文本文件):
上面是一个C版的dll文件,C++版的dll文件也没什么不一样的地方,唯一的区别就是选择C++接口后,编译器会生成一个类,仔细查看代码你会发现在类名的左侧有 DLLIMPORT 宏修饰,这里的意思是:这个类中所有的东东都将被导出。
最重要的一点是,如果你在CPP代码中调用C接口的dll文件时候,在引入其头文件的时候,一定要加上 extern "C" {} 否则会链接出错。下面是一个标准示例:
6、最后呢,说一下,如何用DEV-C++编写dll文件。(这里以C接口为例,C++一样的)
文件->新建->工程,选择“ DLL选项”,然后选右下角的“C工程”,确定后,编译器为我们生成了两个文件(dll.h、dllmain.c),我们看一下dll.h里面的代码:
代码中的 __declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数,这里为了代码的可读性,用了一个宏 DLLIMPORT 来代替,通俗的说用该宏修饰的数据、函数、类或类成员函数才能被外界调用;另外在dllmain.c中,对应函数的实现前也要加上 DLLIMPORT 宏修饰,必须的。