您的位置:首页 > 其它

动态链接库DLL基础知识

2017-10-10 21:45 246 查看
一、介绍动态链接库的定义和作用:

动态链接库(Dynamic Link Library,DLL)是一个包含可由多个程序同时使用的代码和数据的库。通俗来讲,它就是一个仓库,提供一些可以直接拿来用的变量、函数或者类。

DLL有助于节省内存,DLL文件在编译时不会被包含到可执行文件中,只有调用的时候才被加载到内存中,而使用完成后还可以被卸载(占用内存会被清除),这种调用方法是显示调用方式。

DLL还有一个作用就是起到共享资源的作用,可以在多个进程之间共享,而DLL只被加载一次。(目的也是为了节省内存)

二、函数的调用和链接规范

函数调用规范的作用:在高级语言被编译成机器码时,为了让计算机知道传递参数的个数以及传递方法,而必须有一套规范来协调这种参数传递,这种规范又称为调用约定,

它决定在函数调用时,实参压栈、退栈以及堆栈释放方式和编译后的函数名改编方式。

__stdcall、__cdecl、__fastcall、thiscall、naked call,一般常用为__stdcall,采用从右至左压栈方式,退出时函数中自己清理堆栈,编译器会在函数名前增加一个下划线,后面跟一个@符号,@后面跟一个参数所占的字节数:如:int __stdcall ADD(int a,int b) ,函数编译后变为_ADD@8

链接规范又称编译链接方式,有extern "C"和extern "C++"两种,分别表示:被extern "C"修饰的变量和函数是按照C语言方式编译和链接的。如果是被extern "C"修饰的,编译后函数名与调用方式有关,会根据调用方式不同而添加不同的前后缀。而extern "C++"就是按照C++语言方式编译和链接,编译后函数名与调用方式有关,但是有一点是很大不同的,因为C++存在函数重载,所以识别一个函数的方法是需要有返回值类型、函数名、参数列表类型这3个属性。在函数名的开始是以一个‘?'开头,以@Z结尾,中间是函数名@@YG(返回值类型符号名)(参数类型符号名列表),()可去掉,在这里目的是为了清晰区分内容,其中@@YG是代表标识参数表开始。

例如:void __stdcall foo(int x,int y)被编译后 ?foo@@YGHHH@Z,其中'H'符号名代表int类型。

总共有12个参数类型,详细内容参考网上资料。

三、动态链接库函数的引出

动态链接库函数需要进行引出才可以被其他可执行文件使用。有2种方法:使用def文件和使用_declspec关键字

1.def文件方式

def文件为链接器提供有关被链接程序的导出、属性以及其他方面的信息。(完全不知道说啥)

其实这个文件是新建一个文本文件,然后把文本文件的名字后缀改为.def即为def文件。

说重点:LIBRARY xxx   这条语句表示通知链接程序创建一个DLL文件,它名字为xxx.dll(实际上该文件是没有实际生成,我认为是在编译的那瞬间生成的文件)

EXPORTS

函数名 @ 序号...有多少个函数就写多少个,序号从1开
adc0


这样定义后就可以在外部的可执行文件中引出函数,可用函数名找出函数地址,也可以用序号来找到函数地址。

我们是用函数地址去调用函数的!!!我们是用函数地址去调用函数的!!!一般将它放入一个自定义函数指针中,一定要对应!如何创建自定义函数指针在实例说明-.-

  2.__declspec关键字方式

__declspec(dllexport)这是其中一种关键字方式,是用来从dll导出函数、数据或者对象,以及从dll中导入函数、数据或者对象,基本能实现我们的功能,比较常用的一种方式。

例如:声明的时候要在前面加上这一段关键字,就可以被外部调用了。调用的时候与这个关键字无关,后面会说到如何调用。

四、使用动态链接库

动态链接库编译会生成.dll文件和.lib文件,这2个文件是有用到的,有2种调用方式:显式和隐式

显式方式能节省内存,隐式就不能,显式相当于“动态加载”,需要用到什么函数就加载什么函数,基本是一对一加载,用完就释放占用的内存空间。隐式就是在编译的时候,全部都加载一次,基本跟普通头文件一样,调用方便,跟普通调用函数一样,例如:在动态链接库有一个Add函数,直接用Add(参数列表);这样就可以了。

而显式的有点小麻烦,在函数被调用前,你需要加载函数所在的动态链接库到进程空间(项目)中,LoadLibrary(.dll),.dll代表编译生成的动态链接库的.dll文件,返回的是动态链接库的句柄(标识),这个返回值需要保存于HINSTANCE类型的变量中例如保存在hdll这个变量。(下面有用到)

然后自定义一个函数指针类型 typedef (函数返回值类型)( (调用方式)(*自定义函数指针类型名称))(参数类型列表)

参数类型列表用,分隔开2个相邻的参数类型。例如:我有一个 int __stdcall Add(int a,int b)函数

那么它的自定义函数指针类型为 typedef int (__stdcall(*PROC))(int,int);

生成了这么一个自定义类型后,用该类型定义一个函数指针,用于保存GetProcAddress(动态链接库句柄,"函数名")的返回值,返回值是函数地址!! 例如:PROC proc=(PROC)GetProcAddress(hdll,"Add");这样就保存了一个该函数的函数地址。然后可以用该函数地址调用该函数,实现功能。例如:int result=(*proc)(3,5);这样相当于int result=Add(3,5);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: