动态链接库DLL_第1页
动态链接库DLL_第2页
动态链接库DLL_第3页
动态链接库DLL_第4页
动态链接库DLL_第5页
免费预览已结束,剩余9页可下载查看

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、动态链接库DLL目录动态链接库DLL1目录1DLL 概述3DLL 定义3DLL 的种类3动态链接库和静态链接库的比较3DLL 的特点:3DLL 的基本理论4DLL 入出口函数4DLL 的链接方式4隐式连接4显式链接 DLL6DLL 动态链接库库函数的导出11从 DLL 中导出数据变量12用 VC+ 开发环境生成DLL13用 VC+ 生成 WIN32 DLL13用 VC+ 的 MFC 生成的DLL13使用 DLL14DLL 的使用14DLL 的调试14DLL 概述DLL 特点:要求一个 DEF 文件;要求一个 DllMain() 的入口点,不是 WinMain() ;DLL 可以装入,但不能执行

2、。DLL 定义动态链接库:是应用程序中的一段程序,将它放在一个不同的容器内,是一个可以从主.exe文件中单独执行的模块.可以认为一个DLL就是其它应用程序在执行时,能够动态链接和调用的一组服务或函数.DLL中存放的一般是一些公共的子程序段或各种资源和数据.一个最大的特点: 可以实现应用程序本地化 .如在 DLL 中封装了各种语言,在安装时进行适当的选择就能实现本地化.DLL 的种类主要有 Win32 DLL和 MFC APPWizard DLL两大类及相关子类。动态链接库和静态链接库的比较动态链接:在应用程序中不需要包含所要调用函数的代码,而只需要所调信息,如 DLL 位置及相应的函数名。与函

3、数的链接到编译或运行时进行。静态链接: 应用程序必须从静态链接库中取得所需调用函数的代码,程序的可执行代码中。如一般的库函数调用则属此类。DLL 函数的一些并把这些代码放在应用DLL 的特点:? 有利于不同的应用程序共享数据和资源;? 多个应用程序可以使用内存中的动态链接库的单一映射,从而节约了程序运行和内存空间;? 通过使用动态链接库,应用程序可以拆分为相对独立的功能模块,有利于应用程序的升级;? 当多个应用程序需要使用相同的函数时,通过使用动态链接库,可以节约大量的硬盘空间。DLL 的基本理论应用程序在使用DLL 中的内容之前, 系统要调用入出口函数完成DLL 的初始化和终止工作。DLL

4、入出口函数1、DllMain 函数 :在一个 DLL 的调用和撤除时被调用, 一般发生在应用程序使用 LoadLibrary 和 FreeLibrary 等函数及进程经线程启动和终止时。函数结构为:BOOLAPIENTRYDllMain(HINSTANCEhInstance,DWORDfdwReason,LPVOID lpvReserved)Switch (fdwReason)Case DLL_PROCESS_ATTACH:break;/DLL映射到进程地址空间Case DLL_THREAD_ATTACH:break;/一个线程被创建Case DLL_THREAD_DETACH:break;/

5、线程退出Case DLL_PROCESS_DETACH:break;/DLL 从进程中解除映射 Return TRUE;其中hInstance 是 DLL的模块句柄, lpvReserved 指定DLL初始化和清除的一些内容指针,fdwReason 表明调用 DllMain() 函数的原因 ,具体如下 :标志值含义DLL_PROCESS_ATTACH1当一个 DLL 首次装入进程的地址空间时发送DLL_THREAD_A TTACH2在连接 DLL 的进程中生成一个新线程时发送DLL_THREAD_DETACH3在连接 DLL 的进程中一个线程终止时发送DLL_PROCESS_DETACH0在应

6、用程序终止或显式调用FreeLibrary() 使 DLL脱离进程的地址空间时发送MFC 的 Regular DLL 入出口在 MFC 的 DLL 使用中 ,已编好了 DllMain() 函数 ,用户不必写 ,在装载 DLL 时调用其成员函数InitInstance, 在 DLL 退出时调用成员函数ExitInstance, 所需要的初始化和终止工作在这两个函数中完成 .DLL 的链接方式DLL 中包含一个或多个函数 ,调用这些函数的过程和编译 ,链接的方式包括显式连接和隐式链接。隐式连接!原理:先说明 DLL 的导入库文件(lib), 因在库文件包含了一系列指向动态链接库的指针.应用程序通过

7、库文件和DLL 链接 ,调用 DLL 中的函数 .应用程序在调用DLL 时需以下信息 :1.包含导出函数以及类声明的头文件,需要知道函数名和函数接口信息.2. DLL 的导入库文件 ,应用程序在编译链接需要 .3. 实际的 DLL 文件 ,应用程序在运行时调用它 . 具体做法:第一步,代码声明。有几种导出成员函数的方法用 extern 进行修饰,实例代码如下:extern int add(int a, int b);extern int subtract(int a, int b);void CDllTextDlg:OnButton1()/ TODO: Add your control not

8、ification handler code hereCString str;str.Format("3+5=%d",add(3,5);MessageBox(str);void CDllTextDlg:OnButton2()/ TODO: Add your control notification handler code here CString str; str.Format("3-5=%d",subtract(3,5); MessageBox(str);或者: (后者专门针对动态链接库,效率更高)_declspec(dllimport) int a

9、dd(int a, int b);_declspec(dllimport) int subtract(int a, int b);或者:使用dll 生成方提供的头文件。头文件 dll1.h :(这个文件 dll 生成者不一定需要,仅供调用者使用,告诉他们这个 dll 定义了哪些方法和变量 )_declspec(dllimport) int add(int a, int b);_declspec(dllimport) int subtract(int a, int b);调用方:#include "./dllp1/dll1.h"第二步,添加Link 库文件Dll 文件生成的同

10、时,一个 .lib 链接库文件也会生出。其功能是间接调用者的程序和文件,它描述了 dll 的基本状况。dll第三步:部署dll文件到调用者能找到的位置。显式链接 DLL原理 :应用程序在运行时通过函数调用来显式装载和卸载DLL, 并通过函数指针来调用函数 ,这种方式主要用于灵活控制DLL 库动态装入和装出的场合.DLL的导出使用 :第一步:调用函数LoadLibrary 或 AfxLoadLibrary装载 DLL 并得到模块句柄.原型如下 :HINSTANCE LoadLibrary(LPCSTR lpLibFileName);参数为要装入的DLL 的文件名字 .当此函数被多次调用时据,系统

11、通过计数器来标识.第二步:调用函数GetProcAddress 来获得导出函数的指针,在进程中只有一份.函数原型如下:DLL 程序和数FARPROC GetProcAddress(HMODULE hModul,LPCSTR lpProName);hMoudul 是 DLL 的实例句柄,参数lpProName 是相应的函数名。第三步:在使用完后调用函数FreeLibrary 或 AfxFreeLibrary来释放 DLL.FreeLibrary 原型为BOOL FreeLibrary ( HINSTANCE hInstLib);参数是装入的DLL 模块的句柄,调用一次,DLLDLL 占用的空间。

12、好处:a)不需要其它文件(例如link 时的 .libb)速度较快,但耗费资源计数器值减一,最终回到文件);0,系统释放被Code:void Cdll_testDlg:OnBnClickedButton1()/ TODO: 在此添加控件通知处理程序代码HINSTANCE hInst;hInst=LoadLibrary(L"dll1.dll" );typedef int (*ADDPTR)( int a,int b); / 定义一个函数指针ADDPTR add; /add 函数指针变量if (hInst!=NULL)/载入 DLL 成功add=(ADDPTR)GetProcA

13、ddress(hInst,"add");/ 去除 dll 中函数名为add 的这个函数的地址/如果发生了函数的名字改编这里是不是就会失败啊!if(NULL!=add)/ 找到 DLL 中的 add 函数CString str;/*注意:因为这里编译器默认定义了unicode 了吧 ,解决办法如下Format ( L"%c",s ) ;或者 Format ( _T("%c"),s ) ;*/str.Format(L "5+3=%d" ,add(5,3);MessageBox(str); elseMessageBox(

14、L "获取函数地址失败" ); elseMessageBox(L "加载 DLL 失败 ");Note :GetProcAddress 方法因为是运行时载入,没有编译名字改编,所有使用的名字必须是dll 中的改编后的名字。最好是都不改。关于头文件1,dll生成者不一定需要,可以提供给使用dll的 client ,因为他们一般不知道dll内部有哪些函数和变量可以使用,因而在他们的程序内定义变量和函数比较麻烦。2, 当然,这个头文件也可以供dll 生成者使用,以提供一些辅助功能。这样dll 生成方和调用者使用,而两者可以实现不同的功能。例如:.h文件同时供头

15、文件:dll1.h#ifdef DLL1_API#else#define DLL1_API _declspec(dllimport)#endifDLL1_API int add(int a, int b);DLL1_API int subtract(int a, int b);源文件:#define DLL1_API _declspec(dllexport)#include "dll1.h"DLL1_API int add (int a, int b)return a+b;DLL1_API int subtract(int a, int b)return a-b;成员类的导

16、出和导入导出:在头文件中定义,然后再实现头文件 dll1.h#ifdef DLL1_API#else#define DLL1_API _declspec(dllimport)#endifDLL1_API int add(int a, int b);DLL1_API int subtract(int a, int b);class DLL1_API Pointpublic:void output(int x, int y);源文件 dll1.cpp#define DLL1_API _declspec(dllexport)#include "dll1.h"#include &l

17、t;windows.h>#include <stdio.h>DLL1_API int add (int a, int b) DLL1_API int subtract(int a, int b) void Point:output(int x, int y)HWND hwnd=GetForegroundWindow();/ 获得调用者的窗口的句柄,当前正在使用的窗口 HDC hdc=GetDC(hwnd);char buf20;memset(buf,0,20);sprintf(buf,"x=%d,y=%d",x,y);/字符数组的格式化TextOut(hd

18、c,0,0,buf,strlen(buf);ReleaseDC(hwnd,hdc);调用:更新头文件,lib 文件, dll 文件,然后实现调用代码:#include "./dllp1/dll1.h"void CDllTextDlg:OnButton3() / TODO: Add your control notification handler code herePoint pt;pt.output(5,3);导出类的部分方法:class Pointpublic:DLL_API void output(int x, int y);Void output2(int x, i

19、nt y);不同编译器( C vs C+ )的名字改编为了实现重载, C+ 编译器会对函数名进行名字改编, 这个规则是一定的。 如果再由 C 程序去调用,会找不到函数。 而如果采用同样的 C+ 编译器,因为他知道转换后的名字会是什么,所以能找到。但是不同的 C+ 编译器可能会因为改编规则不同而无法访问。因此,有时候希望名字不变。代码:dll1.h#ifdef DLL1_API#else#define DLL1_APIextern "C" _declspec(dllimport)#endifDLL1_API int add(int a, int b);DLL1_API int

20、 subtract(int a, int b);dll1.cpp#define DLL1_APIextern "C" _declspec(dllexport)#include "dll1.h"#include <windows.h>#include <stdio.h>DLL1_API int add (int a, int b)return a+b;DLL1_API int subtract(int a, int b)return a-b;使用 dump 观察函数名:E:VCC-spacedllp1Debug>dumpbin

21、 -exports dllp1.dllCopyright (C) Microsoft Corp 1992-1998. All rights reserved.Dump of file dllp1.dllFile Type: DLLSection contains the following exports for dllp1.dll0 characteristics4AB228D6 time date stamp Thu Sep 17 20:17:26 20090.00 version1 ordinal base2 number of functions2 number of namesord

22、inal hint RV Aname1 0 0000100A add2 1 00001005 subtractSummary4000 .data1000 .idata2000 .rdata2000 .reloc28000 .text如果不加“ extern “C”,结果会是:ordinal hint RV Aname210000100A ?addY AHHHZ4300001005 ?subtractYAHHHZNote:a)Extern“ C”不适合类的成员函数b)调用约定发生改变,函数名也会变化。例如下面的实现,_stdcall导致编译约定被设置为 pascal 的编译方式,名字会改变:源文

23、件:DLL1_API int _stdcall add (int a, int b)return a+b;DLL1_API int _stdcall subtract(int a, int b) return a-b;头文件DLL1_API int _stdcall add(int a, int b);DLL1_API int _stdcall subtract(int a, int b);使用 dumpbin 观察的结果: (下划线 +函数名 + 参数字节数(这里两个int 为 8 字节)ordinal hint RV Aname1 0 00001005 _add82 1 0000100A

24、_subtract8c) C,C+ ,delphi 调用带来的混乱和不便,可通过模块定义文件来解决DLL 动态链接库库函数的导出动态链接库中的函数可以分为导出函数和内部函数。动态链接库中的函数主要有以下几种:( 1) 在源程序中使用关键字: _declspec(dllexport).此函数可从一个DLL 中输出数据 ,函数 ,类,类成员函数而不需要DEF 文件 .原 理 : 根 据 一 个 指 定 的 存 储 类 属 性 (extended-attribute) 存 储 某 个 项 数 据 . 其 属 性 主 要有:allocate( “segname”),dllimport,dllexpor

25、t,naked等 ,语法如下 :_declspec(extended_attribute) declarator;具体使用有二种情况:i. _declspec(dllexport) void_cdecl Function1(void);ii.Class _declspec(dllexport) CExportCLass:public Cobject.(2)在DEF文件中通过EXPORTS来声明函数DEF 是由一个或多个描述DLL 属性的语句组成的文本文件,主要有:LIBRARY语句:用于指定DLL 的内部名;DESCRIPTION语句:用于描述DLL 特性;SECTIONS 语句:用于设置段的

26、属性,这些属性有:READ , WRITE , EXECUTE , SHARED ;EXPORTS 语句:用于列出被导出的函数名及相关信息;VERSION 语句:该 DLL 的版本号。例:LIBRARY “ Dll ”DESCRIPTION ,Dll Windows Dynamic Link Library?EXPORTSFunction1 1Function2 2Function3 3EXPORTS . .库函数的声明如下:Entryname=internalname ordinalNONAME外部名内部名序号不输出函数名模块定义文件的特点a)改变编译环境(例如对函数名加“_stdcall”

27、),名字不便,仍然是def 文件中定义从 DLL 中导出数据变量( 1) 使用 DEF 文件 ,设置关键字 CONSTANT 导出 .通过用 CONSTANT 标志时 ,表明前面导出的不是函数 ,而是一个数据变量 .EXPORTSBvariable 4 CONSTANTExtern BOOLbVariable;/程序中的应用(2)可以在应用程序中使用关键字_declspec(dllimport) 引入对 DLL导出的变量的作用 ,在 DLL 源程序中以 _declspec(dllexport) 来说明要导出的变量 .用 VC+ 开发环境生成 DLL用 VC+ 生成 WIN32 DLL1. Wi

28、n 32 的 DLL 自动生成过程 :FILE->NEW->PROJECT->Win32 Dynamic-Link Library->ok,然后选择相应的类型工程.2.DLL工程类型 :空 DLL 工程:在需要时编写程序源文件,和 DEF 文件简单的DLL 工程:只有DllMain(), 没有导出和其它变量或函数编译后也不产生LIB 文件 .,不生成DEF文件 ,导出变量 ,函数和类的DLL :较为详细地建立了DLL中的一些基本成分,包括导出关键字 _declspec(dllexport), 生成 LIB 文件 .用 VC+ 的 MFC 生成的 DLL1. MFC 类库的 DLL 自动生成过程 :FILE->NEW->PROJECT->MFC AppWizard(dll)->ok,然后选择相应的类型工程。2.MFC AppWizardDLL 类型静态链接MFC 的 Regular DLL在内部使用 MFC 的 DLL 库 ,可被 MFC 和非 MFC 的应用程序使用 ,若在工程建立时使用的是 MFC 静态库 ,导出函数使用标准 C 语言接口 ,创建时自动生成 DEF 文件 ,如导出函数 :MyExportFunction() 用 :extern“ c” EXPORT M

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论