MFC的DLL
- 格式:docx
- 大小:31.57 KB
- 文档页数:16
mfc 扩展dll用法MFC(Microsoft Foundation Classes)是Microsoft提供的一套用于构建Windows图形用户界面(GUI)应用程序的C++类库。
MFC扩展DLL (Dynamic Link Library)通常用于在MFC应用程序中引入额外的功能或模块,以便于代码的组织和模块化。
以下是使用MFC扩展DLL的一般步骤:1.创建MFC DLL项目:在Visual Studio中,您可以选择创建一个MFC DLL项目。
这会生成一个具有MFC支持的DLL项目的基本框架。
2.实现DLL功能:在DLL项目中,您可以添加或实现所需的功能和类。
这些功能可以包括窗口、对话框、控件、业务逻辑等。
3.导出功能:对于需要在DLL外部使用的函数或类,需要在其声明前添加AFX_EXT_CLASS宏,以便正确导出。
例如:class AFX_EXT_CLASS MyExportedClass {//...};extern "C" AFX_EXT_CLASS void AFXAPI MyExportedFunction();4.生成DLL:构建DLL项目以生成DLL文件。
5.在主应用程序中使用DLL:在MFC主应用程序项目中,您需要做以下操作:•将DLL的头文件包含到主应用程序中。
•将DLL的.lib文件链接到主应用程序项目。
•将DLL的.dll文件与主应用程序的可执行文件放在相同的目录或系统路径下。
6.调用DLL中的功能:在主应用程序中,您可以通过类似以下方式调用DLL中的函数或使用DLL中的类:#include "MyDLL.h"//...MyExportedFunction(); // 调用DLL中的函数MyExportedClass myObj; // 创建DLL中的类的实例7.清理:在主应用程序中确保正确处理DLL资源的加载和释放,以避免内存泄漏等问题。
7.MFC的DLL一般的,在介绍Windows编程的书中讲述DLL的有关知识较多,而介绍MFC的书则比较少地提到。
即使使用MFC来编写动态链接库,对于初步接触DLL的程序员来说,了解DLL的背景知识是必要的。
另外,MFC提供了新的手段来帮助编写DLL程序。
所以,本节先简洁的介绍有关概念。
1.DLL的背景知识1.静态链接和动态链接当前链接的目标代码(.obj)如果引用了一个函数却没有定义它,链接程序可能通过两种途径来解决这种从外部对该函数的引用:∙静态链接链接程序搜索一个或者多个库文件(标准库.lib),直到在某个库中找到了含有所引用函数的对象模块,然后链接程序把这个对象模块拷贝到结果可执行文件(.exe)中。
链接程序维护对该函数的所有引用,使它们指向该程序中现在含有该函数拷贝的地方。
∙动态链接链接程序也是搜索一个或者多个库文件(输入库.lib),当在某个库中找到了所引用函数的输入记录时,便把输入记录拷贝到结果可执行文件中,产生一次对该函数的动态链接。
这里,输入记录不包含函数的代码或者数据,而是指定一个包含该函数代码以及该函数的顺序号或函数名的动态链接库。
当程序运行时,Windows装入程序,并寻找文件中出现的任意动态链接。
对于每个动态链接,Windows装入指定的DLL并且把它映射到调用进程的虚拟地址空间(如果没有映射的话)。
因此,调用和目标函数之间的实际链接不是在链接应用程序时一次完成的(静态),相反,是运行该程序时由Windows完成的(动态)。
这种动态链接称为加载时动态链接。
还有一种动态链接方式下面会谈到。
1.动态链接的方法链接动态链接库里的函数的方法如下:∙加载时动态链接(Load_time dynamic linking)如上所述。
Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SYSTEM目录→Windows目录→PATH环境变量指定的路径。
mfc.dll丢失的解决方法
当MFC.dll 文件丢失时,可以采取以下方法来解决问题:
1.重新安装MFC 库:可以尝试重新安装Microsoft Foundation Classes (MFC) 库,以恢复丢失的MFC.dll 文件。
可以从Microsoft 的官方网站下载MFC 安装程序,然后按照提示进行安装。
2.从备份中恢复:如果已经备份了MFC.dll 文件,可以将其从备份中复制到正确的位置,以替换丢失的文件。
请确保备份的文件与当前系统兼容,并且位于正确的文件夹中。
3.使用DLL 修复工具:可以使用DLL 修复工具来恢复丢失的MFC.dll 文件。
这些工具可以从网上免费下载,但请注意选择可信的网站和工具。
使用DLL 修复工具时,请按照提示操作,并确保选择正确的修复选项。
4.检查杀毒软件和防火墙设置:有时,杀毒软件或防火墙设置可能会阻止MFC.dll 文件的正常加载。
可以暂时禁用杀毒软件或防火墙,然后再次尝试加载MFC.dll 文件。
5.检查系统路径设置:如果系统路径设置不正确,可能会导致找不到MFC.dll 文件。
可以检查系统路径设置,确保MFC.dll 文件位于正确的位置。
1.新建MFC DLL工程,取名为:DLL0410
动态链接库的创建和调用(类,函数的DLL导出和调用)
2.在工程中编辑好DLL0410.h,DLL0410.cpp,DLL0410.def三个文件后编译生成对应的dll和lib文件
2.1 DLL0410.h
2.2 DLL0410.cpp
2.3 DLL0410.def
2.4 编辑好上面的3个文件编译后,用dumpbin命令查看是否有函数导出。
(如图所示,sub全局函数和add类的成员函数已经导出)
3.新建一个工程DLL0410test将生成的DLL0410.dll,DLL0410.lib以及DLL0410.h文件拷贝到 DLL0410test工程目录下
4.静态调用:在工程的DLL0410test.cpp文件中导入头文件DLL0410.h,并编写对应的静态调用代码。
同时也要在工程属性链接中加入DLL0410.lib文件。
(如果编译出错有可能是,工程属性中的常规>>字符集>>修改为 使用多字节字符集)
运行成功
5.4.动态调用:只需将生成的DLL0410.dll文件拷贝到新建工程目录下,直接在工程的
DLL0410test.cpp中编写动态调用代码即可。
不用做其他任何连接和导入头文件的操作。
运行成功。
MFC 下DLL 编程(图解)DLL (Dynamic Link Library ,动态链接库)是微软公司为Windows 和OS/2操作系统设计一种供应用程序在运行时调用的共享函数库。
DLL 是应用程序的一种扩展,也是软件共享和重用的传统方法。
DLL 除了可同时被多个应用程序共享外,还可以在不改变调用接口(从而不需修改使用它的应用程序)的情况下,改进和升级里面的库函数。
而且DLL 与编写它的语言无关,例如,用VC 生成的规则DLL ,可以被VB 、Delphi 等生成的应用程序使用。
DLL 可以用多种语言和工具编写,我们这里只介绍如何使用MFC 来编写和使用DLL 。
相关说明文档位于MSDN 帮助的“目录\开发工具和语言\Visual Studio\Visual C++\常见编程方法\DLL\”中。
8.1 基础本节先讨论DLL 与静态库的区别,然后列出几种适合放置DLL 的目录,最后介绍MFC DLL 的三种类型。
8.1.1 DLL 与静态链接库静态链接库Lib (Static Link Library ),是在编译的链接阶段将库函数嵌入到应用程序的内部。
如果系统中运行的多个应用程序都包含所用到的公共库函数,则必然造成很大的浪费。
这样即增加了链接器的负担,也增大了可执行程序的大小,还加大了内存的消耗。
Lib 的好处是应用程序可以独立运行,而不需要在操作系统中另外安装对应的DLL 。
而DLL 采用动态链接,对公用的库函数,系统只有一个拷贝(一般是位于系统目录的*.DLL 文件),而且只有在应用程序真正调用时,才加载到内存。
在内存中的库函数,也只有一个拷贝,可供所有运行的程序调用。
当再也没有程序需要调用它时,系统会自动将其卸载,并释放其所占用的内存空间。
参见图8-1。
图8-1 静态库函数与动态链接库的区别DLL 的缺点是应用程序不能独立运行,需要在操作系统中另外安装对应的DLL 。
例如,如果你的MFC 项目被设置成“在共享DLL 中使用MFC ”的,则虽然生成的可执行程序很使用静态库函数使用动态链接库小,但是在其他没有安装Visual C++(运行环境)的机器上是不能直接运行的,需要另外安装MFC的动态链接库(如mfc90.dll)。
第4节我们对非MFC DLL进行了介绍,这一节将详细地讲述MFC规则DLL的创建与使用技巧。
5. MFC规则DLL5.1 概述MFC规则DLL的概念体现在两方面:(1)它是MFC的“是MFC的”意味着可以在这种DLL的内部使用MFC;(2)它是规则的“是规则的”意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是其与应用程序的接口不能是MFC。
而MFC扩展DLL与应用程序的接口可以是MFC,可以从MFC扩展DLL中导出一个MFC类的派生类。
Regular DLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。
在这种动态连接库中,包含一个从CWinApp继承下来的类,DllMain函数则由MFC自动提供。
Regular DLL分为两类:(1)静态链接到MFC 的规则DLL静态链接到MFC的规则DLL与MFC库(包括MFC扩展DLL)静态链接,将MFC库的代码直接生成在.dll文件中。
在调用这种DLL的接口时,MFC使用DLL的资源。
因此,在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。
使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码。
(2)动态链接到MFC 的规则DLL动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到MFC DLL 和任何MFC扩展DLL。
在使用了MFC共享库的时候,默认情况下,MFC使用主应用程序的资源句柄来加载资源模板。
这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。
因此,对于共享MFC DLL的规则DLL,我们必须进行模块切换以使得MFC能够找到正确的资源模板。
我们可以在Visual C++中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。
如图8,依次选择Visual C++的project -> Settings -> General菜单或选项,在Microsoft Foundation Classes中进行设置。
题目:MFC调用DLL报无法解析的外部符号近年来,随着Windows操作系统的广泛应用,MFC(Microsoft Foundation Class)作为Windows开发的重要工具之一,广泛应用于软件开发领域。
而调用动态信息库(Dynamic Link Library,简称DLL)则是在MFC开发过程中常见的操作。
但是在实际开发中,经常会遇到MFC调用DLL时报“无法解析的外部符号”的问题,给开发者带来了不少困扰。
本文将从以下几个方面探讨MFC调用DLL报无法解析的外部符号的原因及解决方法。
一、了解外部符号的概念外部符号是指在C/C++语言中通过函数或变量名表达的标识符。
在编写程序时,当我们使用其他模块或库中定义的函数或变量时,就需要使用外部符号来声明或引用这些函数或变量。
二、分析出现“无法解析的外部符号”的原因1. 头文件未正确包含当在MFC项目中调用DLL的函数或变量时,首先要确保在MFC项目中正确包含了相关头文件。
有时,因为头文件路径设置不正确,或者头文件名称与DLL中的定义不一致,导致无法解析外部符号的错误。
2. 函数或变量未导出在创建DLL时,需要明确指定哪些函数或变量是可以被外部调用的,这就需要使用`__declspec(dllexport)`来声明导出函数或变量。
如果在DLL中未正确导出需要调用的函数或变量,就会出现无法解析外部符号的错误。
3. 使用C++编译器与信息器在MFC项目中调用DLL时,要确保使用相同的C++编译器与信息器。
有时,因为使用了不同版本或不兼容的编译器与信息器,导致在信息过程中无法解析外部符号。
4. 函数或变量名称冲突在MFC项目和DLL中,如果存在相同名称的函数或变量,就会出现名称冲突的问题,导致无法解析外部符号。
三、解决“无法解析的外部符号”的方法1. 检查头文件路径与名称确保在MFC项目中正确包含了DLL的头文件,并且头文件路径和文件名与DLL中的定义一致。
mfc110u.dll是什么意思
dll是电脑程序运行的重要支持文件。
如果出现了某个dll的丢失那么就会有对应支持的电脑程序无法进行运行了。
所以mfc110u.dll是什么意思?就很简单,它是一个系统文件。
mfc110u.dll是什么意思
系统运行文件
1、mfc100u.dll是windows系统的运行重要文件。
2、这个dll文件是支持系统运行的,非常的重要。
3、这类文件一般是不能轻易修改的,可能会导致系统崩溃。
4、此类文件出错可能会导致电脑出现如桌面图标无法删除、网络游戏打不开、电脑无故蓝屏、电脑没声音和桌面无法显示等各种问题。
dll都是电脑系统文件,对操作系统或者是某个电脑程序的运行起到重要的支持作用。
MFC中引用DLLDLL的背景知识静态链接和动态链接 当前链接的目标代码(.obj)如果引用了一个函数却没有定义它,链接程序可能通过两种途径来解决这种从外部对该函数的引用:静态链接 链接程序搜索一个或者多个库文件(标准库.lib),直到在某个库中找到了含有所引用函数的对象模块,然后链接程序把这个对象模块拷贝到结果可执行文件(.exe)中。
链接程序维护对该函数的所有引用,使它们指向该程序中现在含有该函数拷贝的地方。
动态链接 链接程序也是搜索一个或者多个库文件(输入库.lib),当在某个库中找到了所引用函数的输入记录时,便把输入记录拷贝到结果可执行文件中,产生一次对该函数的动态链接。
这里,输入记录不包含函数的代码或者数据,而是指定一个包含该函数代码以及该函数的顺序号或函数名的动态链接库。
当程序运行时,Windows装入程序,并寻找文件中出现的任意动态链接。
对于每个动态链接,Windows装入指定的DLL并且把它映射到调用进程的虚拟地址空间(如果没有映射的话)。
因此,调用和目标函数之间的实际链接不是在链接应用程序时一次完成的(静态),相反,是运行该程序时由Windows完成的(动态)。
这种动态链接称为加载时动态链接。
还有一种动态链接方式下面会谈到。
动态链接的方法 链接动态链接库里的函数的方法如下:加载时动态链接(Load_time dynamic linking) 如上所述。
Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SYSTEM目录→Windows目录→PATH环境变量指定的路径。
运行时动态链接(Run_time dynamic linking) 程序员使用LoadLibrary把DLL装入内存并且映射DLL到调用进程的虚拟地址空间(如果已经作了映射,则增加DLL的引用计数)。
首先,LoadLibrary搜索DLL,搜索顺序如同加载时动态链接一样。
然后,使用GetProcessAddress 得到DLL中输出函数的地址,并调用它。
MFC创建动态链接库DLL并调⽤⽅法详解实例⼀:1、创建⼀个动态链接库⼯程,如login_dll。
2、在原⼯程头⽂件或者新建头⽂件如showdlg.h定义动态链接库的导出函数,代码如下:#include "stdafx.h"#define EXPORT __declspec(dllexport)extern "C" EXPORT void __stdcall Showdialg(char* pText);3、在动态链接库源⽂件中定义showdialog函数,代码如下:void _stdcall Showdialg(char* pText){MessageBox(NULL,pText,"提⽰⼀",0);}注:此步编译后,即可⽣成dll与lib⽂件,因为_stdcall是⼀种⽐较流⾏的函数调⽤约定,(或者可以不⽤_stdcall),如果使⽤的时候,为了防⽌发⽣函数命令改编的情况,可以定义⼀个.def⽂件,其中加⼊EXPORTS节,设置导出函数名,如下所⽰:LIBRARY "login_dll"EXPORTSShowdialg = Showdialg4、创建⼀个基于对话框的⼯程。
5、定义⼀个函数指针类型,其定义与动态链接库的函数原型相同,代码如下:typedef void (__stdcall * funShowInfo)(char* pchData);6、处理按键单击事件,加载动态链接库,代码如下:void Cuse_login_dllDlg::OnBnClickedOk(){HMODULE hMod = LoadLibrary("login_dll.dll");if (hMod != NULL){funShowInfo ShowInfo;ShowInfo = (funShowInfo)GetProcAddress(hMod,"Showdialg");if (ShowInfo)ShowInfo("传⼊参数成功且调⽤正常");}FreeLibrary(hMod);}其中,第5步与第6步是通过LoadLibrary函数动态加载链接库的⽅法,下⾯介绍⼀下静态加载链接库的⽅法:1、加载链接库的头⽂件,将动态链接库头⽂件拷贝到当前⼯程中,并在当前⼯程头⽂件进⾏声明。
1.打开VS2012,依次选择文件—新建—项目—MFC DLL,在下方名称栏中输入工程命名OneDLL,在位置栏中选择存放工程文件的路径—确定—点击下一步—DLL类型:使用共享MFC DLL 的规则DLL—点击完成。
2. 其中我们感兴趣的是OneDLL.cpp文件和OneDLL. def文件。
OneDLL.cpp文件是DLL的主要的源代码文件,它包含了COneDLLApp类的定义;OneDLL.def文件包含了DLL提供的关于DLL在Wind ows下运行的一些信息,在这个文件中定义了一些参数,如DLL的名称和属性等,还声明了从DLL中输出的函数。
3.添加实现代码,黑色加粗部分为添加的代码。
#include "stdafx.h"#include "OneDLL.h"#ifdef _DEBUG#define new DEBUG_NEW#endifint Message(void);BEGIN_MESSAGE_MAP(COneDLLApp, CWinApp)END_MESSAGE_MAP()// COneDLLApp 构造COneDLLApp::COneDLLApp(){// TODO: 在此处添加构造代码,// 将所有重要的初始化放置在InitInstance 中}// 唯一的一个COneDLLApp 对象COneDLLApp theApp;// COneDLLApp 初始化BOOL COneDLLApp::InitInstance(){CWinApp::InitInstance();return TRUE;}int Message(void){MessageBox(NULL,_T("This is the example of testing DLL."),NULL,MB_OKCANCEL);return 1;}记得设为为多字节而非unicode编码。
反编译mfc的dll文件今天讨论两个问题第一如何反编译dll,第二如何将反编译的文件生成dll。
反编译dll安装vs,最好是最新版本的,如果要反编译的dll使用新版本创建的,也能反编译成功。
下面是详细的反编译步骤。
1.打开C:\Program Files\MicrosoftSDKs\Windows\v6.0A\bin\ildasm.exe,这个程序是微软提供的反编译软件,打开要反编译的dll。
2.然后选择文件-转储,这时会弹出转储选项的对话框(一般按照默认即可),设定好以后选择转储位置。
3.完成后会生成以res和il结尾的文件,还有可能包含以.resources结尾的文件。
这样我们就将dll反编译完成。
根据需要修改il文件。
如何反编译.resources文件呢选择开始-所有程序-vs安装文件夹-vs tools-开发人员命令提示符,然后在弹出的dos窗口下输入resgen 1.resources 1.resx,这样resources文件变转化成可以编辑的resx文件。
组合dll先说如何将resx文件组合成resources文件选择开始-所有程序-vs安装文件夹-vs tools-开发人员命令提示符,然后在弹出的dos窗口下输入resgen 1.resx 1.resources,这样resx文件变转化成可以编辑的resources文件。
选择开始-所有程序-vs安装文件夹-vs tools-开发人员命令提示符,然后在弹出的dos窗口下输入ilasm /dll/resource=1.res 1.il,注意res文件和il文件位置不可以改变,这样就生成了想要的dll。
mfcdll导出函数
MFCDLL是指使用MFC(Microsoft Foundation Classes)编写的动态链接库文件。
在MFCDLL中,可以使用以下方法导出函数:
- 使用模块定义文件(.def):该文件包含一个或多个描述DLL各种属性的模块语句。
DEF文件必须至少包含以下模块定义语句:文件中的第一个语句必须是LIBRARY语句,用于将.def文件标识为属于DLL。
- 使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS:这两种方法互斥,对每个函数只需使用一种方法即可。
使用MFCDLL导出函数时,需要根据具体的需求和应用场景选择合适的方法。
如果你还需要了解MFCDLL的其他内容,可以继续向我提问。
中定义和使用MFCDLL基础教程基础实例VC++.NET中定义和使用MFC DLL什么是DLL?DLL指的是动态链接库(Dynamic Link Library),它是一个可以被多个应用程序(甚至是不同语言编写的应用程序)同时调用的可执行二进制文件,是一个可共享的库。
DLL是建立在客户/服务器通信的概念上,包含若干函数、类或资源的库文件,函数和数据被存储在一个DLL(服务器)上并由一个或多个客户导出而使用,这些客户可以是应用程序或者是其它的DLL。
在下面我们将通过一个具体的例子来说明如何利用定义一个DLL文件,并且在的应用程序中调用,这个例子的主要功能是通过DLL获取系统的机器名、操作系统类型和IP地址。
在中定义DLL文件选择菜单项,选择文件->新建->项目,在弹出的新建项目的对话框中,选择项目类型为Visual C++ 项目,类别为MFC的工程,在右边的模板中,选择MFC DLL模板,给项目取名为T estDLL,选择好项目的位置,按确定健,进入应用程序设置。
在应用程序设置中,我们可以看到,有三种DLL类型,它们依次对应着三类DLL。
静态DLL与共享DLL的区别是:前者使用的是MFC的静态链接库,生成的DLL文件长度大,一般不使用这种方式,后者使用MFC的动态链接库,生成的DLL文件长度小;动态链接到MFC的共享DLL 所有输出的函数应该以如下语句开始(用于正确切换MFC模块状态):AFX_MANAGE_STATE(AfxGetStaticModuleState( )) 扩展DLL用来建立MFC的派生类,只被用MFC类库所编写的应用程序调用。
常规DLL(包括静态与动态)的一个特点是在源文件里有一个继承CWinApp的类(从CWinApp派生,但没有消息循环),被导出的函数是C++类或者C++成员函数,调用常规DLL的应用程序不必一定是MFC应用程序。
扩展DLL和常规DLL不一样,它没有一个从CWinApp继承而来的类的对象,编译器默认了一个DLL入口函数DLLMain()作为对DLL的初始化。
mfc dll库内的结构导出
DLL(动态链接库)是一种可执行文件,它可以被程序调用以执行特定的任务。
MFC(微软基础类库)是一个提供了大量常用类和函数的C++类库,它可以用于开发Windows应用程序。
在MFC中,有多种类型的DLL,其中MFC Regular DLL和MFC Extension DLL都可以导出MFC类库中的结构。
MFC Regular DLL包含一个继承自CWinApp的类,但其没有消息循环。
MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。
要导出MFC DLL库内的结构,你可以遵循以下步骤:
1. 选择“Mfc AppWizard(dll)”,在右边的“Project name”下输入“ExportClass”,单击“下一步”。
2. 选择“Mfc Extension DLL(using shared MFC DLL)”,单击“完成”。
3. 在DLL项目中,选择“ClInclude”文件夹,并在其下添加新的头文件。
4. 在头文件中声明要导出的类、函数和变量。
5. 在DLL项目的cpp文件中实现导出的类、函数和变量。
通过上述步骤,你可以成功地导出MFC DLL库内的结构,并使其他应用程序能够访问和使用它们。
mfc dll 回调函数MFC(Microsoft Foundation Class)是一种用于Windows操作系统的C++编程框架。
它结合了许多常用的GUI(图形用户界面)组件和函数,使得开发者可以更轻松地创建Windows应用程序。
在MFC中,可以使用DLL(动态链接库)来封装一组共享的功能,并且可以通过回调函数来实现与MFC应用程序的交互。
回调函数是一种由调用方提供给被调用方的函数,用于在特定事件发生时执行。
MFC中的回调函数可以通过函数指针、成员函数指针以及函数对象等形式传递。
以下是在MFC中使用DLL和回调函数的一般步骤:1. 创建一个DLL项目,并实现所需的功能函数。
2. 在DLL项目中定义回调函数,以供MFC应用程序调用。
回调函数可以是静态函数、全局函数或类成员函数等形式。
3. 在MFC应用程序中,通过使用LoadLibrary函数加载DLL,并使用GetProcAddress函数获取回调函数的地址。
4. 将回调函数的地址传递给DLL中的相应函数,以便在特定事件发生时调用回调函数。
以下是一个简单的示例:在DLL项目中的头文件中定义回调函数:```cpp// MyDLL.htypedef void (__cdecl *CallbackFunction)(int);extern "C" __declspec(dllexport) voidSetCallback(CallbackFunction callback);extern "C" __declspec(dllexport) void DoSomething(); ```在DLL项目中的源文件中实现功能函数和回调函数:```cpp// MyDLL.cpp#include "MyDLL.h"static CallbackFunction g_callback = nullptr;extern "C" __declspec(dllexport) voidSetCallback(CallbackFunction callback){g_callback = callback;}extern "C" __declspec(dllexport) void DoSomething() {// 执行一些功能处理// ...// 如果回调函数存在,则调用回调函数if (g_callback != nullptr)g_callback(10); // 传递一个参数给回调函数}}```在MFC应用程序中加载DLL并使用回调函数:```cpp// MyMFCAppDlg.cpp#include "MyMFCAppDlg.h"#include "MyDLL.h"...// 回调函数void MyCallback(int value){// 在回调函数中处理接收到的参数}...// 加载DLL,并获取回调函数的地址HMODULE hModule = LoadLibrary(_T("MyDLL.dll"));if (hModule != NULL){CallbackFunction callback =(CallbackFunction)GetProcAddress(hModule, "SetCallback"); if (callback != nullptr)// 设置回调函数callback(&MyCallback);}}...// 调用DLL中的功能函数CallbackFunction DoSomethingFunc =(CallbackFunction)GetProcAddress(hModule, "DoSomething");if (DoSomethingFunc != nullptr){DoSomethingFunc();}...// 在需要卸载DLL时,使用FreeLibrary函数FreeLibrary(hModule);```这是一个简单的示例,实际使用中可能涉及到更复杂的操作和错误处理。
MFC的DLL一般的,在介绍Windows编程的书中讲述DLL的有关知识较多,而介绍MFC的书则比较少地提到。
即使使用MFC来编写动态链接库,对于初步接触DLL的程序员来说,了解DLL的背景知识是必要的。
另外,MFC提供了新的手段来帮助编写DLL程序。
所以,本节先简洁的介绍有关概念。
1.DLL的背景知识1.静态链接和动态链接当前链接的目标代码(.obj)如果引用了一个函数却没有定义它,链接程序可能通过两种途径来解决这种从外部对该函数的引用:∙静态链接链接程序搜索一个或者多个库文件(标准库.lib),直到在某个库中找到了含有所引用函数的对象模块,然后链接程序把这个对象模块拷贝到结果可执行文件(.exe)中。
链接程序维护对该函数的所有引用,使它们指向该程序中现在含有该函数拷贝的地方。
∙动态链接链接程序也是搜索一个或者多个库文件(输入库.lib),当在某个库中找到了所引用函数的输入记录时,便把输入记录拷贝到结果可执行文件中,产生一次对该函数的动态链接。
这里,输入记录不包含函数的代码或者数据,而是指定一个包含该函数代码以及该函数的顺序号或函数名的动态链接库。
当程序运行时,Windows装入程序,并寻找文件中出现的任意动态链接。
对于每个动态链接,Windows装入指定的DLL并且把它映射到调用进程的虚拟地址空间(如果没有映射的话)。
因此,调用和目标函数之间的实际链接不是在链接应用程序时一次完成的(静态),相反,是运行该程序时由Windows完成的(动态)。
这种动态链接称为加载时动态链接。
还有一种动态链接方式下面会谈到。
1.动态链接的方法链接动态链接库里的函数的方法如下:∙加载时动态链接(Load_time dynamic linking)如上所述。
Windows搜索要装入的DLL时,按以下顺序:应用程序所在目录→当前目录→Windows SYSTEM目录→Windows目录→PATH环境变量指定的路径。
∙运行时动态链接(Run_time dynamic linking)程序员使用LoadLibrary把DLL装入内存并且映射DLL到调用进程的虚拟地址空间(如果已经作了映射,则增加DLL的引用计数)。
首先,LoadLibrary搜索DLL,搜索顺序如同加载时动态链接一样。
然后,使用GetProcessAddress得到DLL中输出函数的地址,并调用它。
最后,使用FreeLibrary减少DLL的引用计数,当引用计数为0时,把DLL模块从当前进程的虚拟空间移走。
1.输入库(.lib):输入库以.lib为扩展名,格式是COFF(Common object file format)。
COFF标准库(静态链接库)的扩展名也是.lib。
COFF格式的文件可以用dumpbin来查看。
输入库包含了DLL中的输出函数或者输出数据的动态链接信息。
当使用MFC创建DLL程序时,会生成输入库(.lib)和动态链接库(.dll)。
2.输出文件(.exp)输出文件以.exp为扩展名,包含了输出的函数和数据的信息,链接程序使用它来创建DLL动态链接库。
3.映像文件(.map)映像文件以.map为扩展名,包含了如下信息:模块名、时间戳、组列表(每一组包含了形式如section::offset的起始地址,长度、组名、类名)、公共符号列表(形式如section::offset的地址,符号名,虚拟地址flat address,定义符号的.obj文件)、入口点如section::offset、fixup列表。
4.lib.exe工具它可以用来创建输入库和输出文件。
通常,不用使用lib.exe,如果工程目标是创建DLL程序,链接程序会完成输入库的创建。
更详细的信息可以参见MFC使用手册和文档。
5.链接规范(Linkage Specification )这是指链接采用不同编程语言写的函数(Function)或者过程(Procedure)的链接协议。
MFC所支持的链接规范是“C”和“C++”,缺省的是“C++”规范,如果要声明一个“C”链接的函数或者变量,则一般采用如下语法:#if defined(__cplusplus)extern "C"{#endif//函数声明(function declarations)…//变量声明(variables declarations)#if defined(__cplusplus)}#endif所有的C标准头文件都是用如上语法声明的,这样它们在C++环境下可以使用。
6.修饰名(Decoration name)“C”或者“C++”函数在内部(编译和链接)通过修饰名识别。
修饰名是编译器在编译函数定义或者原型时生成的字符串。
有些情况下使用函数的修饰名是必要的,如在模块定义文件里头指定输出“C++”重载函数、构造函数、析构函数,又如在汇编代码里调用“C””或“C++”函数等。
修饰名由函数名、类名、调用约定、返回类型、参数等共同决定。
1.调用约定调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。
MFC 支持以下调用约定:1._cdecl按从右至左的顺序压参数入栈,由调用者把参数弹出栈。
对于“C”函数或者变量,修饰名是在函数名前加下划线。
对于“C++”函数,有所不同。
如函数void test(void)的修饰名是_test;对于不属于一个类的“C++”全局函数,修饰名是?test@@ZAXXZ。
这是MFC缺省调用约定。
由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。
2._stdcall按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。
对于“C”函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。
对于“C++”函数,则有所不同。
所有的Win32 API函数都遵循该约定。
3._fastcall头两个DWORD类型或者占更少字节的参数被放入ECX和EDX 寄存器,其他剩下的参数按从右到左的顺序压入栈。
由被调用者把参数弹出栈,对于“C”函数或者变量,修饰名以“@”为前缀,然后是函数名,接着是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是@func@12。
对于“C++”函数,有所不同。
未来的编译器可能使用不同的寄存器来存放参数。
4.thiscall仅仅应用于“C++”成员函数。
this指针存放于CX寄存器,参数从右到左压栈。
thiscall不是关键词,因此不能被程序员指定。
5.naked call采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。
naked call不产生这样的代码。
naked call不是类型修饰符,故必须和_declspec共同使用,如下:__declspec( naked ) int func( formal_parameters ){// Function body}6.过时的调用约定原来的一些调用约定可以不再使用。
它们被定义成调用约定_stdcall或者_cdecl。
例如:#define CALLBACK __stdcall#define WINAPI __stdcall#define WINAPIV __cdecl#define APIENTRY WINAPI#define APIPRIVATE __stdcall#define PASCAL __stdcall表7-1显示了一个函数在几种调用约定下的修饰名(表中的“C++”函数指的是“C++”全局函数,不是成员函数),函数原型是void CALLTYPE test(void),CALLTYPE可以是_cdecl、_fastcall、_stdcall。
表7-1 不同调用约定下的修饰名1.MFC的DLL应用程序的类型1.静态链接到MFC的规则DLL应用程序该类DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。
输入函数有如下形式:extern "C" EXPORT YourExportedFunction( );如果没有extern “C”修饰,输出函数仅仅能从C++代码中调用。
DLL应用程序从CWinApp派生,但没有消息循环。
2.动态链接到MFC的规则DLL应用程序该类DLL应用程序里头的输出函数可以被任意Win32程序使用,包括使用MFC的应用程序。
但是,所有从DLL输出的函数应该以如下语句开始:AFX_MANAGE_STATE(AfxGetStaticModuleState( ))此语句用来正确地切换MFC模块状态。
关于MFC的模块状态,后面第9章有详细的讨论。
其他方面同静态链接到MFC的规则DLL应用程序。
3.扩展DLL应用程序该类DLL应用程序动态链接到MFC,它输出的函数仅可以被使用MFC 且动态链接到MFC的应用程序使用。
和规则DLL相比,有以下不同:1.它没有一个从CWinApp派生的对象;2.它必须有一个DllMain函数;3.DllMain调用AfxInitExtensionModule函数,必须检查该函数的返回值,如果返回0,DllMmain也返回0;4.如果它希望输出CRuntimeClass类型的对象或者资源(Resources),则需要提供一个初始化函数来创建一个CDynLinkLibrary对象。
并且,有必要把初始化函数输出。
5.使用扩展DLL的MFC应用程序必须有一个从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的上述特点。
1.DLL的几点说明1.DLL应用程序的入口点是DllMain。
对程序员来说,DLL应用程序的入口点是DllMain。
DllMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL 的每一个进程或者线程不再使用DLL或者结束时,都会调用DllMain。