动态链接库

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

应用程序与动态链接库之间的区别尽管DLL和应用程序都是可执行的程序模块,但他们之间还是有若干不同之处。对于最终用户来说,最明显的差异在于DLL不是可直接执行的程序。从系统角度来说,应用程序和DLL之间有两个基本差异:应用程序可以有多个同时在系统上运行的实例,而DLL只能有一个实例。应用程序可以拥有堆栈、共用内存、文件句柄、消息队列等,而DLL没有。DLL的优点DLL(dynamic-linklibrary)是由函数和数据组成的模块,可以应用与其他模块(应用程序或者DLL)中。DLL动态链接库可以定义两种函数:内部函数和导出函数。正如它所定义的一样,导出函数可以由其他模块调用。内部函数只能由动态链接库自己来调用。虽然,DLL也可以导出数据,但这些数据通常还是给动态链接库内部的函数使用的。当然,其他模块还是可以给通过这些数据地址来读写这些数据。DLL类型非MFCDLL非MFCDLL是内部不使用MFC的DLL,这类DLL中的导出函数可由MFC或非MFC可执行文件调用。函数通常是通过标准C接口从非MFCDLL导出的。静态链接到MFC的规则DLL静态链接到MFC的规则DLL是在内部使用MFC的DLL,这类DLL中的导出函数可由MFC或非MFC可执行文件调用。正如名称所述,这类DLL是使用MFC静态链接库版本生成的。函数通常通过标准C接口从规则DLL中导出。静态链接库到MFC的规则DLL具有如下功能:客户端执行文件可以用任何支持使用DLL的语言(C、C++、Pascal、VisualBasic等)编写;它不必是MFC应用程序。DLL可以链接到由应用程序使用的同一MFC静态链接库。已不再有单独用于DLL的静态链接库版本。在MFC4.0版之前,USRDLL与静态链接到MFC的规则DLL提供相同的功能类型。自VisualC++4.0版起,“USRDLL”一词已过时。静态链接到MFC的规则DLL具有下列要求:这类DLL必须从CWinApp派生的类中实例化。此类型的DLL使用MFC提供的DllMain。与标准MFC应用程序一样,将所有DLL特定的初始化代码放到InitInstance成员函数中,将所有终止代码放到ExitInstance中。尽管“USRDLL”一词已过时,但仍必须在编译器命令行上定义“_USRDLL”。此定义确定从MFC头文件中复制的声明。与MFC应用程序相同,规则DLL必须有一个由CWinApp派生的类和此应用程序类的单个对象。然而,与应用程序的CWinApp对象不同,DLL的CWinApp对象没有主消息泵。另外,CWinApp::Run机制不适用于DLL,因为应用程序有着消息泵。如果DLL打开无模式对话框或有自己的主框架窗口,则应用程序的主消息泵必须调用由DLL导出的例程,而该例程应而该例程应会反过来调用DLL应用程序对象的CWinApp::PreTranslateMessage成员函数。符号通常是通过标准C接口从规则DLL导出的。从规则DLL导出的函数的声明形如:extern“C”_declspec(dllexport)MyExportedFunction();规则DLL内的所有内存分配都应该在DLL内进行;DLL不应向调用可执行文件传递或从从DLL中导出函数.Dll文件的布局与.exe文件非常相似,但有一个非常重要的差异:DLL文件包含导出表。导出表包含DLL导出到其他可执行文件的每一个函数的名称。这些函数时DLL中的入口点,只有导出表中的函数可以由其他可执行文件访问。DLL中的任何其他函数都是DLL私有的。通过/EXPORTS选项的Dumpbin工具可以,查看DLL的导出表。DLL导出函数的两种方法:1、在生成DLL时,创建一个模块定义(.def)文件并使用该.def文件。如果希望按序号而不是按名称从DLL导出函数,则使用此方法。2、在函数定义中使用_declspec(dllexport)关键字。注:用以上两种方法导出函数时,还需确保_stdcall的调用约定。使用模块定义(.def)文件从DLL中导出函数模块定义文件(.def)是包含一个或多个描述DLL各种属性的Module语句的文本文件。如果不使用_declspec(dllexport)关键字导出DLL函数,则DLL需要.def文件。.def文件必须包含下列定义语句:1、文件中的第一个语句必须是LIBRARY语句。此语句将.def文件标识为属于DLL。LIBRARY语句后面是DLL的名称。连接器将此名称放到DLL的导入库中。2、EXPORTS语句列出名称,可能的话还会列出DLL导出函数的序号值。通过在函数名的后面加上@符合一个数字,给每个函数分配序号值。当指定序号值时,序号值的范围必须是1到N,其中N是DLL导出函数的个数。下面是一个二进制搜索树的代码的DLL例子:LIBRARYBTREEEXPORTSInsert@1Delete@2Member@3Min@4如果使用MFCDLL向导创建MFCDLL,则向导会创建一个主干.def文件,并将自动添加到项目中,并添加要导出此文件的函数名。对于非MFCDLL则需自己创建.def文件并将其添加到项目中。要导出C++文件中的函数,必须将修饰名放到.def文件中,或者通过使用外部”C”定义具有标准C连接的导出函数。如果需要将修饰名放到.def文件中,则可以通过使用DUMPBIN工具或者/MAP连接器选项来获取修饰名。使用_declspec(dllexport)从DLL中导出函数_declspec(dllexport)会将导出文件添加到对象文件中,因此不需要使用.def文件。由于对名称修饰没有标准规范,因此导出函数的名称在不同编译版本可能有所变化。如果使用_declspec(dllexport),仅当命名约定更改时才必须重新编译DLL和依赖.exe文件。许多导出指令(如序号,NONAME和PRIVATE)只能在.def文件中创建,并且必须使用.def文件来制定这些特性。不过,在.def的基础上使用_declspec(dllexport)不会导致生成错误。若要导出函数,_declspec(dllexport)关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:_declspec(dllexport)void_cdeclFunction1(void);若要导出类中所有的公共成员和成员函数,关键字必须出现在类名的左边,如下所示:class_declspec(dllexport)CExampleExport:publicCObject{…classdefinition…};注:_declspec(dllexport)不能应用于具有_clrcall调用约定的函数。生成DLL时,通常创建一个包含正在导出的函数原型或者类的头文件,并将_declspec(dllexport)添加到头文件的声明中。若要提高代码的可读性,请为_declspec(dllexport)定义一个宏并对正在导出的每个符号使用该宏:#defineDllExport_declspec(dllexport)_declspec(dllexport)将函数名存储在DLL的导出表中。将可执行文件链接到DLL中可执行文件以显示链接或者隐式链接两种方式链接或(加载)到DLL中。隐式链接也称静态加载或加载时动态链接。显示链接又称动态加载或者运行时动态链接。在隐式链接下,使用DLL的可执行文件链接到该DLL的创建者所提供的导入库(.lib文件)。DLL的可执行文件加载时,是通过操作系统来加载此DLL的。客户端可执行文件调用DLL的导出函数,就好像这些函数包含在可执行文件内一样。在显示链接下,使用DLL的可执行文件必须进行函数调用以显示加载和卸载该DLL,并访问该DLL的导出函数。客户端可执行文件必须通过函数指针调用导出函数。可执行文件可以用两种方法调用同一个DLL。同样,可以一个可执行文件隐式链接到一个DLL,另一个可执行文件显示链接到此DLL,这些机制不是互斥的。隐式链接为隐式链接到DLL,可执行文件必须从DLL的提供程序获取下列各项:1、包含导出函数或C++类的声明的头文件。类、函数和数据应均具有_declspec(dllimport)2、要链接的导入库(.LIBfiles)3、实际的DLL(.dll文件)。使用DLL的可执行文件必须包括头文件,此头文件包含每个源文件中的导出函数(或C++类),而这些源文件包含对导出函数的调用。从编码角度讲,导出函数的函数调用与任何其他函数调用一样。若要生成调用可执行文件,必须与导入库链接。如果使用的是外部生成文件,请指定导入库的文件名,此导入库中列出了要链接到的其他对象(.obj)文件或库。操作系统在加载调用可执行文件时,必须能够定位DLL文件。显示链接在显示链接下,应用程序必须进行函数调用以在运行时显示加载DLL。为显示链接到DLL,应用程序必须:1、调用LoadLibrary(或相近的函数)以加载DLL和获取模块句柄。2、调用GetProcAddress,以获取指向应用程序要调用的每一个导出函数的函数指针。由于应用程序是通过指针调用DLL的函数,编译器不生成外部引用,故无需与导入库链接。3、使用DLL后调用FreeLibrary。例子:typedefUINT(CALLBACK*LPFNDLLFUNC1)(DWORD,UINT);...HINSTANCEhDLL;//HandletoDLLLPFNDLLFUNC1lpfnDllFunc1;//FunctionpointerDWORDdwParam1;UINTuParam2,uReturnVal;hDLL=LoadLibrary(MyDLL);if(hDLL!=NULL){lpfnDllFunc1=(LPFNDLLFUNC1)GetProcAddress(hDLL,DLLFunc1);if(!lpfnDllFunc1){//handletheerrorFreeLibrary(hDLL);returnSOME_ERROR_CODE;}else{//callthefunctionuReturnVal=lpfnDllFunc1(dwParam1,uParam2);}}

1 / 5
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功