•动态链接库在Windows中非常重要,几乎所有的WindowsAPI函数都包含在动态链接库中。•动态链接库有很多优点,如节省内存、支持多语种等,特别是当动态链接库(DLL)中的函数改变后,只要不是参数改变,调用这个函数的应用程序就不需要重新编译,这在编程时是十分有用的。DLL基本理论12.1简单DLL示例12.2访问动态链接库12.3常规DLL12.4扩展DLL12.512.1DLL基本理论•在Windows操作系统中,几乎所有的内容都是以DLL的形式存在的。•例如显示的字体和图标存储在GDI.DLL中;显示Windows桌面、处理用户输入所需要的代码被存储在User.DLL中;Windows编程所需要的大量API函数存储在Kernel.DLL中。12.1.1DLL基本概念•应用程序要从目标代码(.obj)外部引用函数,可以通过两种途径实现——静态链接和动态链接。1.静态链接•该种方式下,链接程序首先对库文件(.lib)进行搜索,直到在某个库中,找到包含函数的对象模块为止。•然后,链接程序把这个对象模块复制到可执行文件(.exe)中。•链接程序负责维护对该函数的所有引用。2.动态链接•该种方式下,链接程序同样先对库文件(.lib)进行搜索,直到在某个库中,找到所引用函数的输入记录为止。•动态链接库主要有如下优点:•(1)系统中,同时运行的多个应用程序可以同时使用同一个动态链接库,它们在内存中共享DLL文件的一个拷贝。•这样做不仅节省了内存,而且减少了文件的动态交换。•(2)只要编写的应用程序的函数变量、返回值的类型、数量不发生变化,动态链接库的函数可以不用重新编译链接,直接使用。•(3)只要遵循一定的规则,不同语言编写的应用程序可以调用同一个动态链接库。12.1.2DLL的分类•微软的VisualC++支持3种DLL,它们分别是Non-MFCDLL(非MFCDLL)、RegularDLL(常规DLL)和ExtensionDLL(扩展DLL)。•1.Non-MFCDLL(非MFCDLL)•2.RegularDLL(常规DLL)•3.ExtensionDLL(扩展DLL)12.1.3DLL的工作原理•应用程序打开动态链接库时,把动态链接库的执行代码映射到进程的地址空间中,这里的进程包括了使用动态链接库的每一个进程。•而动态链接库中的数据,应用程序则不是通过映射方式获取,而是做了一个备份。•也就是说动态链接库所有的执行代码是共享的,但其中的变量,每个应用程序均备份了一份。•1.文件映射•2.引用表•3.内存分配12.2简单DLL示例•DLL现在越来越容易编写,Win32已经大大简化了其编程模式,并有许多来自AppWizard和MFC类库的支持。•本节将从一个简单的非MFCDLL实例入手,讨论DLL的一些主要编程思想。12.2.1一个简单的DLL•1.DLL的编程实现图12.1工程向导•2.DLL调用的编程实现•3.例程分析图12.2对话框窗口设计图12.3程序运行结果12.2.2导出函数•DLL文件中包含一个导出函数表,给出了DLL中每个导出函数的名字和标识号。•另外,函数表中还包含了DLL中函数的地址。•动态链接过程将在加载DLL模块时,动态建立一个函数调用与函数地址的对应表。•因此,如果没有改变导出函数的名字和参数序列,则重新编译或重建DLL文件时并不需要修改应用程序。•从DLL导出函数主要有两种方式:•(1)创建模块定义文件(.def),并把导出函数名加入模块定义文件中;•(2)在定义函数时使用_declspec(dllexport)关键字。1.使用模块定义文件导出函数•模块定义文件是一个由多个语句组成的文本文件,根据不同的DLL,其模块定义语句可以不同,但一般来说必须包含以下语句:•(1)LIBRARY语句。•(2)DESCRIPTION语句。•(3)EXPORTS语句。2.使用_declspec(dllexport)关键字输出DLL•用户可以使用_declspec(dllexport)关键字输出DLL里的数据、函数、类等,这样就不再需要DEF文件了。12.2.3导入函数•DLL中实现了导出函数,而在应用程序中,必须声明相应的导入函数。•不论DLL中采用的是DEF文件输出方式,还是_declspec(dllexport)输出方式,在应用程序中都可以用_declspec(dllimport)关键字来导入函数。•采用_declspec(dllimport)关键字导入函数MyFunction(),实现如下:•void_declspec(dllimport)MyFunction();12.3访问动态链接库•在应用程序中访问DLL,实际上就是将应用程序中的导入函数与DLL文件中的导出函数进行链接。•有两种链接方式:隐式链接和显式链接。•隐式链接是指通过编译器,给应用程序提供DLL的名称和DLL函数的链接地址;显式链接则由应用程序通过代码加载DLL,编译器不需要知道任何关于DLL的信息。12.3.1隐式链接•要实现对DLL的隐式链接,应用程序要从DLL提供者处获得以下3个文件:•(1)包含有关DLL输出函数声明的头文件;•(2)DLL的导入库(.LIB)文件;•(3)动态链接库(.DLL)文件。12.3.2显式链接•显式链接方式要求应用程序以函数的形式实时地装入DLL,其实现过程可表示如下:•(1)调用Win32的LoadLibary()函数,指定DLL的路径作为参数,函数将返回DLL模块的句柄;•(2)调用GetProcAddress()函数,获取应用程序希望访问的DLL函数的入口指针;•(3)通过DLL函数指针访问DLL函数;•(4)当DLL使用完后,调用FreeLibrary()函数来卸载DLL。•1.获取DLL的句柄•2.获取函数的内存地址•3.卸载动态链接库•4.判断动态链接库是否被装入系统•5.显示链接示例6.链接方式的选择•采用隐式链接,应用程序EXE文件被加载时,会将其调用的所有DLL文件加载在到内存中;但如果采用显式链接,程序员可以决定DLL文件何时加载或不加载。•也就是说,显式链接在运行时决定加载哪个DLL文件。12.4常规DLL•MFC中的常规DLL可分为两种——静态链接到MFC的常规DLL和动态链接到MFC的常规DLL。•二者的区别是:前者使用的是MFC的静态链接库,生成的DLL文件长度大;后者使用MFC的动态链接库,生成的DLL文件长度小。12.4.1静态链接到MFC的常规DLL•1.利用MFCAppWizard生成工程•2.添加实现代码•3.编译链接图12.4工程向导图12.5选择DLL类型12.4.2动态链接到MFC的常规DLL•1.利用MFCAppWizard生成工程•2.添加实现代码•3.编译链接图12.6选择DLL类型12.4.3DLL的链接使用•应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接。•隐式链接就是在程序开始执行时就将DLL文件加载到应用程序当中。•实现隐式链接很容易,只要将导入函数的关键字_declspec(dllimport)和函数名写到应用程序对应的头文件中即可。•而后就可以直接使用函数MsgBox()。•与隐式链接相比,显式链接具有更好的灵活性。•1.生成工程•2.创建资源•3.添加代码•4.编译运行图12.7TestDLL窗体设计图12.8链接StaticMFCDll.dll结果图12.9链接ShareMFCDill.dll结果12.5扩展DLL•MFC中扩展DLL的特点是用来建立MFC的派生类,该DLL只能被用MFC类库所编写的应用程序调用。•扩展DLL和常规DLL不一样,它没有一个从CWinApp继承而来的类的对象,编译器创建了一个DLL入口函数——DLLMain(),可以在此函数中实现DLL的初始化。•同样可以通过MFCAppWizard[dll]方式生成扩展DLL,和MFC常规DLL一样,下面同样实现一个扩展DLL,其导出函数为MsgBox(),弹出一个对话框,显示创建的DLL的类型(即扩展MFCDLL)。12.5.1生成DLL•1.建立工程•2.添加代码•3.编译运行图12.10选择DLL类型12.5.2链接DLL•和常规MFCDLL的链接实例一样,这里也采用显式链接。图12.11测试链接程序运行窗体图12.12链接ExtentionDLL.dll结果小结•本章主要介绍了MFC常规DLL和扩展DLL。•常规DLL又可细分成静态链接到MFC的DLL和动态链接到MFC的DLL两种。•扩展DLL是用MFC的动态链接版本所创建的,只被用MFC类库所编写的应用程序所调用。•本章在介绍DLL基本原理的基础上,着重讲解了DLL的编程思想,重点介绍了常规DLL和扩展DLL的基本概念及其创建、调用过程,并给出了相关的开发、调用实例。上机指导•实验一:创建一个简单的DLL•实验内容•创建一个简单的DLL,对输入的数值进行乘法运算。•实验目的•熟悉创建DLL的过程与步骤。•实现思路•参照12.2节例子,创建一个DLL。但是计算两个数值的乘法的代码,需要读者重新编写。•实验二:显式链接•实验内容•显式链接实验一创建的DLL。•实验目的•熟悉显式链接的过程与常用的链接函数。•实现思路•参照12.3.2节中示例的链接步骤,与实验一创建的DLL创建链接。