LIB和DLL

来源:互联网 发布:centos6.5 yum源配置 编辑:程序博客网 时间:2024/04/28 17:19

一 概述

.lib和.dll都是二进制文件,便于代码冲重用。lib是编译时需要的,dll是运行时需要的。

一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。在使用.lib之前,要在程序源代码中引用lib对应的头文件.h,这些头文件告诉编译器.lib中有什么。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。

在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行时再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。

二 Win32 DLL的创建

创建

1 首先,利用VC创建一个Win32 Dynamic-Link Library类型的工程DLL1,选择“An empty Dll project”,即创建一个空的动态链接工程。

2 然后,为该工程添加一个C++源文件:DLL1.cpp,并在其中编写一个完成加法运算和一个减法运算的函数,代码如下:

_declspec(dllexport)int add(int a,int b)
{
    return a + b;
}
_declspec(dllexport)int subtract(int a,int b)
{
    return a - b;
}

利用Build命令生成DLL1这一动态连接库程序,之后在工程的Debug目录下,可以看到生成了Dll1.dll文件(动态链接库文件),引入库文件Dll1.lib文件(该文件中保存的是Dll.dll中导出的函数和变量的符号名)和Dll1.exp文件(输出库文件,不重要)。

查看 Dumpbin

为了查看一个DLL中有哪些导出函数,可以利用Visual Studio提供的命令行工具:Dumpbin来实现。(Dumpbin.exe文件位于Visual Studio安装目录下的vc98/bin目录下)在命令行界面下输入Dumpbin命令,回车,即可列出该命令的使用方法。

如果想要查看一个DLL提供的导出函数可以使用/EXPORTS选项来运行Dumpbin命令:在Dll1.dll文件所在目录下,在命令提示行输入 dumpbin -exports dll1.dll  即可看到该命令输出了一些信息。

注意:这里为了让DLL导出一些函数,需要在每一个将要被导出的函数前面添加标识符:_declspec(dllexport)。一定要知道:应用程序如果想要访问某个DLL中的函数,那么该函数必须是已经被导出的函数。加_declspec(dllexport)的目的就是让DLL导出此函数,并生成.lib文件。如果不加,则利用Build命令只生成Dll1.dll,利用Dumpbin命令也看不到任何与函数有关的信息(说明没有导出函数)。

头文件怎么创建?静态链接库呢?

三 隐式链接方式加载DLL

这时,我们看到DLL1.dll已经导出了两个函数:add和subtract,可以编写一个基于对话框的MFC测试程序DllTest。调用步骤

1 编写代码

首先利用extern声明外部函数。在调用DLL1.dll中的add和subtract函数之前,为了让编译器知道这两个函数,需要对这两个函数作一个声明(前面加上extern关键字表明函数是在外部定义的):

extern int add(int a, int b);
extern int subtract(int a, int b);

注:除了使用extern关键字表明函数是外部定义的之外,还可以使用标识符:_declspec(dllimport)来表明函数是从动态链接库中引入的。与extern关键字相比,使用_declspec(dllimport)标示符声明外部函数时,编译器能够生成运行效率更高的代码。

然后编写调用函数如:(注:extern声明语句应该放在add和subtract函数调用之前)

void CDLLTestDlg::OnBnClickedBtnAdd()
{
    CString str;
    str.Format(_T("5+3=%d"),add(5,3));
    MessageBox(str);
}

2 Build

利用Build命令生成DllTest会出现三个错误,类似erro LINK2001:unresolved external symbol... 程序编译通过(因为这里调用的add和subtract函数都已经做了声明,所以编译通过),错误是在程序链接时发生的。在链接时,连接器需要知道这两个函数到底在哪个地点实现的,他要找到这两个函数的实现。正因为没有找到该信息,所以链接出错了!

为了解决这个问题,就需要利用动态链接库的引入库文件(.lib)。将DLL1.lib复制到DllTest程序所在的目录,这个文件就包含了Dll1.dll中导出函数的符号名。然后在DllTest程序中选择【Properties】--->Linker --->Input--->Additional Dependencies(vc2005) 添加DLL1.lib。此时Build成功生成DllTest.exe文件。也就是说,当程序需要调用某个动态链接库提供的函数时,在程序链接时只需要包含该动态链接库提供的导入库文件(.lib)就可以了。导入库文件没有包含实际的代码,它只是用来链接程序提供的必要信息,以便在可执行文件中建立动态链接时需要用到的重定位表。

我们可以查看可执行程序的输入信息,以及加载的DLL信息,同样可以用dumpbin命令:进入DllTest.exe文件所在目录,在命令行输入 dumpbin -imports dlltest.exe 我们将会看到改程序调用到的DLL。

3 运行

再次运行DllTest.exe,会出先错误提示对话框,提示在指定路径下找不到动态链接库Dll1.dll文件。

由于应用程序运行时,系统将为它分配一个4GB的地址空间,然后加载模块分析该应用程序的输入信息,从中找到该程序将要访问的动态链接库信息,然后在用户机器上按一定的搜索顺序和目录搜索这些动态链接库,进而加载它们。如果加载程序未能找到其中任何一个动态链接库,可执行程序将终止运行。因此本例需要将Dll1.dll放置在搜索模块能够搜索到得路径下,例如DllTest工程所在目录下。此时运行程序成功。


 

参考:

1 http://hi.baidu.com/nzahu0214/blog/item/03f735125395c4085baf5349.html

2 VC++深入详解(孙鑫)