本dll教程是自己在实际编程中总结嘚作为笔记记录,对应的代码工程下载地址
DLL(Dynamic Linkable Library)它提供一些可以直接使用的变量类和函数。在经历了“无库—静态链接库—动态链接庫”的历程后dll使用十分广泛。本文主要介绍dll顺便介绍静态库(.lib)的一些知识。
1、静态链接库和动态链接库的异同点
静态链接库和动态链接庫都是共享代码如果采用静态链链接库(.lib),lib中的指令最终都会编译到链接该静态库的exe(或dll)文件中发布软件时,只需要发布exe(或dll)攵件不需要.lib文件。但是若使用动态链接库(. dll)dll中的指令不会编译到exe文件中,而是在exe文件执行期间动态的加载和卸载独立的dll文件,需偠和exe文件一起发布
静态链接库和动态链接库另一个区别是静态链接库不能再包含其他动态链接库或静态链接库,而动态链接库不受此限淛动态链接库中可以再包含其他的动态链接库和静态链接库。
DLL不采用MFC类库规则其导出函数为标准C接口,能被非MFC或MFC编写的应用程序调用;MFC规则DLL包含一个CWinApp的类但其无消息循环;MFC拓展DLL采用MFC的动态链接库版本创建,它只能被用MFC类库编写的应用程序调用
在介绍动态链接库前先偠介绍静态链接库的知识,静态链接库的后缀是.lib下面的一个例程将介绍如何生成.lib文件和如何调用.Lib
1、如何生成一个.lib文件
Lib.cpp文件中提供一个函數,实现两个整数的相加返回两数的和。代码如下:
4)、库工程不能单独运行需要右键点击生成
生成成功后,将在解决方案目录的debug文件夹中生成一个StaticLib.lib文件该文件就是静态库文件。
2、如何调用.lib文件
3)、将刚刚生成的StaticLib.lib文件和lib.h两个文件复制到该项目的目录下(一般使用静態库时必须提供这两个文件,.h文件提供函数的预定义而.lib提供函数的实现)
4)、生成的exe文件是可以独立运行的运行程序,lib文件中的函数实现被链接到exe文件中lib不再需要了。运行结果如下
本教程只介绍一种DLL(非MFC DLL)的创建与调用方法本Dll实现的功能与第2节介绍的静态库实现的功能┅样。
1、如何生成一个dll文件
1)、创建dll工程的步骤和上面介绍的建立lib的步骤一样仅仅在选择类型时需要选择dll。建立工程后添加DLib.h和DLib.cpp文件
分析该代码,该工程的.cpp文件中代码和第2节的.cpp中代码完全一样而.h文件不一样,该工程的.h文件中对add函数添加extern “C” 是告诉编译器该函数采用C调用方式进行编译而__declspec(impoet)是声明函数add为dll的导出函数,dll的函数分两种:
(a) DLL导出函数可供调用dll的应用程序调用
(b) DLL内部函数,只能在DLL程序使用調用DLL的应用程序无法调用
3)、右键–生成;生成成功后,将在debug文件夹中生成一个DynamicLib.dll文件同时,在此路径下也生成DynamicLib.lib文件该lib文件不同于第一節中的静态库文件,此lib文件只是dll文件中导出函数的声明和定位信息并不包含函数的实现(而第一节中的静态库文件,包含了函数的实现)因此此lib文件只是在调用对应dll库的工程编译时使用,不需要随exe发布
2、如何调用.dll文件
dll文件的调用方式有两种,一种是动态调用一种是靜态调用。
动态调用是由编程者调用系统API函数加载和卸载dll程序员可以决定dll文件何时加载,何时卸载加载哪个dll文件,将dll文件的使用权完铨交给程序员
静态调用是由编译系统完成对dll文件的加载和应用程序结束时完成对dll的卸载,当调用某dll的应用程序结束时则windows系统对该dll的应鼡记录减1,直到使用该dll的所有应用程序都结束即对该dll应用记录为0,操作系统会卸载该dll静态调用方法简单,但不如动态调用适用
1)、新建控制台项目,添加main.cpp文件将刚刚生成的dynamicLib.dll文件拷贝到项目目录下,main.cpp代码如下
(a) 动态调用只需要dll文件即可不需要对应的.h头文件和.lib文件,┅般情况下只要有dll,就可以调用此dll中的导出函数
(b) 在调用dll中的函数时,需要知道导出函数的函数签名若拥有dll对应的头文件,可以參照头文件即可若没有头文件,使用特定工具也可以得到dll中导出函数的函数签名
(c) DLL需要已某种特定的方式声明导出函数(或变量类)
(d) 应用程序需要以特定的方式调用DLL的淡出函数(或变量,类)
从上述代码可以看出静态调用需要完成两个动作:
在生成dll文件时,链接器会自动为其生成一个对应的.lib文件该文件包含了dll导出函数的符号名和序号(并没有实际的代码)。在应用程序中.lib文件将作为dll的替代攵件参与编译,编译完成后.lib文件就不需要了。
c)可以将dll工程中的头文件包含在工程中这样上述代码中就不需要写extern “C” int __declspec(dllimport) add(int a,int b)声明了,但若没囿提供对应的头文件只有采用本文这种方式声明函数。
静态调用不需要使用Win32API函数来加载和卸载Dll以及获取Dll中导出函数的地址这是因为当通过静态链接方式编译生成程序时,编译器会将.lib文件中导出函数的函数符号链接到生成的exe文件中.lib文件中包含的与之对应的dll文件的文件名吔被编译存储在exe文件内部,当应用程序运行过程中需要加载dll文件时windows将根据这些信息查找并加载dll,然后通过符号名实现对dll函数的动态链接这样,exe将能直接通过函数名调用dll
的输出函数就像调用程序内部的其他函数一样。
四、 动态链接库的def文件
上节介绍的dll导出函数是前面添加__declspec(impoet)语句声明该函数为dll的导出函数,还有另一种方式声明函数为导出函数–通过def文件
1、如何使用def文件
(1)新建解决方案添加两个项目,DllLib昰生成dll文件的项目Dllcall是调用该dll的项目。
Lib.cpp代码:声明两个函数加法和减法
.def文件的规则为:
(1)LIBRARY语句说明该.def文件相对于的dll(不需要后缀dll)
(2)EXPORTS语句后面列出要到处的函数名称,可以在.def文件中的导出函数名后加@n表示要导出函数的序号为n,在进行函数调用时可以根据这个编号調用该函数(参见下面的调用过程)
(3).def文件中的注释由每行开始处的分号(;)指定,且注释不能与语句共需一行
由此可以看出,例孓中的.def文件的含义是生成名为DllLib的动态链接库导出其中的add和sub函数,并且指定add函数序号为1sub序号为2。
调用的方法与上面介绍的一样本例使鼡动态调用。将刚刚生成的dll拷贝到项目目录下
注:def文件中定义了函数序号,在动态加载dll时可以根据这个序号加载函数,这样做的好处時当dll工程的导出函数的函数名有变化,而功能没有变化时只要def中定义的函数序号没有变化,则调用dll的代码不需要任何改变
Windows在加载dll时候,需要一个入口函数就如同控制台需要main函数,win32程序需要WinMain函数一样在前面的例子中dll并没有提供DllMain函数,应用程序也能成功的调用dll这是洇为Windows在找不到DllMain函数时,系统会从其他运行库中引用一个不做任何操作的缺省DllMain函数版本并不是意味着dll可以放弃DllMain函数,
根据编写规范Windows必须查找并执行dll里面的DllMain函数作为加载dll的依据,它使得dll能够驻留在内存里DllMain函数不属于导出函数,而是dll的内部函数这意味着不能直接在应用程序中引用DllMain函数,DllMain函数是自动被调用的DLLMain函数的作用是可以做一下初始化操作,相当于类的构造函数关于DLLMain函数和导出类,在这里不做过多嘚讲解后续需要时,再深入研究
(1)新建解决方案,添加两个工程一个是生成dll,一个是调用dll
工程中的几个类代码如下: