MFC中引用DLL.doc

上传人:工**** 文档编号:551738873 上传时间:2022-09-12 格式:DOC 页数:4 大小:25.51KB
返回 下载 相关 举报
MFC中引用DLL.doc_第1页
第1页 / 共4页
MFC中引用DLL.doc_第2页
第2页 / 共4页
MFC中引用DLL.doc_第3页
第3页 / 共4页
MFC中引用DLL.doc_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

《MFC中引用DLL.doc》由会员分享,可在线阅读,更多相关《MFC中引用DLL.doc(4页珍藏版)》请在金锄头文库上搜索。

1、MFC中引用DLLDLL的背景知识 静态链接和动态链接 当前链接的目标代码(.obj)如果引用了一个函数却没有定义它,链接程序可能通过两种途径来解决这种从外部对该函数的引用:静态链接 链接程序搜索一个或者多个库文件(标准库.lib),直到在某个库中找到了含有所引用函数的对象模块,然后链接程序把这个对象模块拷贝到结果可执行文件(.exe)中。链接程序维护对该函数的所有引用,使它们指向该程序中现在含有该函数拷贝的地方。动态链接 链接程序也是搜索一个或者多个库文件(输入库.lib),当在某个库中找到了所引用函数的输入记录时,便把输入记录拷贝到结果可执行文件中,产生一次对该函数的动态链接。这里,输入记

2、录不包含函数的代码或者数据,而是指定一个包含该函数代码以及该函数的顺序号或函数名的动态链接库。当程序运行时,Windows装入程序,并寻找文件中出现的任意动态链接。对于每个动态链接,Windows装入指定的DLL并且把它映射到调用进程的虚拟地址空间(如果没有映射的话)。因此,调用和目标函数之间的实际链接不是在链接应用程序时一次完成的(静态),相反,是运行该程序时由Windows完成的(动态)。这种动态链接称为加载时动态链接。还有一种动态链接方式下面会谈到。动态链接的方法 链接动态链接库里的函数的方法如下:加载时动态链接(Load_time dynamic linking) 如上所述。Windo

3、ws搜索要装入的DLL时,按以下顺序:应用程序所在目录当前目录Windows SYSTEM目录Windows目录PATH环境变量指定的路径。运行时动态链接(Run_time dynamic linking) 程序员使用LoadLibrary把DLL装入内存并且映射DLL到调用进程的虚拟地址空间(如果已经作了映射,则增加DLL的引用计数)。首先,LoadLibrary搜索DLL,搜索顺序如同加载时动态链接一样。然后,使用GetProcessAddress得到DLL中输出函数的地址,并调用它。最后,使用FreeLibrary减少DLL的引用计数,当引用计数为0时,把DLL模块从当前进程的虚拟空间移

4、走。输入库(.lib): 输入库以.lib为扩展名,格式是COFF(Common object file format)。COFF标准库(静态链接库)的扩展名也是.lib。COFF格式的文件可以用dumpbin来查看。输入库包含了DLL中的输出函数或者输出数据的动态链接信息。当使用MFC创建DLL程序时,会生成输入库(.lib)和动态链接库(.dll)。输出文件(.exp) 输出文件以.exp为扩展名,包含了输出的函数和数据的信息,链接程序使用它来创建DLL动态链接库。映像文件(.map) 映像文件以.map为扩展名,包含了如下信息:模块名、时间戳、组列表(每一组包含了形式如section:o

5、ffset的起始地址,长度、组名、类名)、公共符号列表(形式如section:offset的地址,符号名,虚拟地址flat address,定义符号的.obj文件)、入口点如section:offset、fixup列表。lib.exe工具 它可以用来创建输入库和输出文件。通常,不用使用lib.exe,如果工程目标是创建DLL程序,链接程序会完成输入库的创建。更详细的信息可以参见MFC使用手册和文档。链接规范(Linkage Specification ) 这是指链接采用不同编程语言写的函数(Function)或者过程(Procedure)的链接协议。MFC所支持的链接规范是“C”和“C+”,缺

6、省的是“C+”规范,如果要声明一个“C”链接的函数或者变量,则一般采用如下语法:#if defined(_cplusplus)extern C#endif/函数声明(function declarations)/变量声明(variables declarations)#if defined(_cplusplus)#endif所有的C标准头文件都是用如上语法声明的,这样它们在C+环境下可以使用。修饰名(Decoration name) “C”或者“C+”函数在内部(编译和链接)通过修饰名识别。修饰名是编译器在编译函数定义或者原型时生成的字符串。有些情况下使用函数的修饰名是必要的,如在模块定义文件

7、里头指定输出“C+”重载函数、构造函数、析构函数,又如在汇编代码里调用“C”或“C+”函数等。修饰名由函数名、类名、调用约定、返回类型、参数等共同决定。调用约定 调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。MFC支持以下调用约定:_cdecl 按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于“C”函数或者变量,修饰名是在函数名前加下划线。对于“C+”函数,有所不同。如函数void test(void)的修饰名是_test;对于不属于一个类的“C+”全局函数,修饰名是?testZAXXZ。这是

8、MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。_stdcall 按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于“C”函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号“”及参数的字节数,如函数int func(int a, double b)的修饰名是_func12。对于“C+”函数,则有所不同。所有的Win32 API函数都遵循该约定。_fastcall 头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于“C”函数或者变量,修饰名以

9、“”为前缀,然后是函数名,接着是符号“”及参数的字节数,如函数int func(int a, double b)的修饰名是func12。对于“C+”函数,有所不同。未来的编译器可能使用不同的寄存器来存放参数。thiscall 仅仅应用于“C+”成员函数。this指针存放于CX寄存器,参数从右到左压栈。thiscall不是关键词,因此不能被程序员指定。naked call 采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。naked call不产生这样的代码。naked call不是类型修饰符,故

10、必须和_declspec共同使用,如下:_declspec( naked ) int func( formal_parameters )/ Function body过时的调用约定 原来的一些调用约定可以不再使用。它们被定义成调用约定_stdcall或者_cdecl。例如:#define CALLBACK _stdcall#define WINAPI _stdcall#define WINAPIV _cdecl#define APIENTRY WINAPI#define APIPRIVATE _stdcall#define PASCAL _stdcall以下显示了一个函数在几种调用约定下的修饰

11、名(表中的“C+”函数指的是“C+”全局函数,不是成员函数),函数原型是void CALLTYPE test(void),CALLTYPE可以是_cdecl、_fastcall、_stdcall。不同调用约定下的修饰名调用约定 extern “C”或.C文件 .cpp, .cxx或/TP编译开关 _cdecl _test ?testZAXXZ _fastcall test0 ?testYIXXZ _stdcall _test0 ?testYGXXZ MFC的DLL应用程序的类型 静态链接到MFC的规则DLL应用程序 该类DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的

12、应用程序。输入函数有如下形式:extern C EXPORT YourExportedFunction( );如果没有extern “C”修饰,输出函数仅仅能从C+代码中调用。DLL应用程序从CWinApp派生,但没有消息循环。动态链接到MFC的规则DLL应用程序 该类DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。但是,所有从DLL输出的函数应该以如下语句开始:AFX_MANAGE_STATE(AfxGetStaticModuleState( )此语句用来正确地切换MFC模块状态。关于MFC的模块状态,后面第9章有详细的讨论。其他方面同静态链接到MFC的规

13、则DLL应用程序。扩展DLL应用程序 该类DLL应用程序动态链接到MFC,它输出的函数仅可以被使用MFC且动态链接到MFC的应用程序使用。和规则DLL相比,有以下不同:它没有一个从CWinApp派生的对象; 它必须有一个DllMain函数; DllMain调用AfxInitExtensionModule函数,必须检查该函数的返回值,如果返回0,DllMmain也返回0; 如果它希望输出CRuntimeClass类型的对象或者资源(Resources),则需要提供一个初始化函数来创建一个CDynLinkLibrary对象。并且,有必要把初始化函数输出。 使用扩展DLL的MFC应用程序必须有一个从

14、CWinApp派生的类,而且,一般在InitInstance里调用扩展DLL的初始化函数。 为什么要这样做和具体的代码形式,将在后面9.4.2节说明。MFC类库也是以DLL的形式提供的。通常所说的动态链接到MFC 的DLL,指的就是实现MFC核心功能的MFCXX.DLL或者MFCXXD.DLL(XX是版本号,XXD表示调试版)。至于提供OLE(MFCOXXD.DLL或者MFCOXX0.DLL)和NET(MFCNXXD.DLL或者MFCNXX.DLL)服务的DLL就是动态链接到MFC核心DLL的扩展DLL。其实,MFCXX.DLL可以认为是扩展DLL的一个特例,因为它也具备扩展DLL的上述特点。

15、DLL的几点说明 DLL应用程序的入口点是DllMain。 对程序员来说,DLL应用程序的入口点是DllMain。DllMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DllMain。但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DllMain。DllMain的函数原型符合DllEntryPoint的要求,有如下结构:BOOL WINAPI DllMain (HANDLE hInst,

16、 ULONG ul_reason_for_call,LPVOID lpReserved)switch( ul_reason_for_call ) case DLL_PROCESS_ATTACH:.case DLL_THREAD_ATTACH:.case DLL_THREAD_DETACH:.case DLL_PROCESS_DETACH:.return TRUE;其中:参数1是模块句柄;参数2是指调用DllMain的类别,四种取值:新的进程要访问DLL;新的线程要访问DLL;一个进程不再使用DLL(Detach from DLL);一个线程不再使用DLL(Detach from DLL)。参数3保留。如果程序员不指定DllMain,则编译器使用它自己的DllMain,该函数仅仅返回T

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 社会民生

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号