赞
踩
MFC常规DLL的创建与使用实例
22.2节中介绍了非MFC DLL的创建和使用实例,与之不同的是,本节介绍内部使用MFC,但是提供的访问接口不支持DLL而是标准的C接口的常规DLL。除了介绍基本概念和创建方法外,本节还介绍MFC常规DLL的创建实例和调用方法。
22.3.1 基本概念
MFC常规DLL,从字面上理解有两点。一是MFC的,这是指DLL内部使用MFC进行编程。二是指其是常规的,这是指此种DLL提供的接口是常规的而不是DLL的。从这种类型的DLL中导出的函数可以被MFC也可以被非MFC应用程序调用,从其中导出的函数使用标准的C接口。
MFC常规DLL具有一个对应的CwinApp对象,并且初始化和析构任务与MFC应用程序的处理位置是相同的,分别在DLL的CwinApp派生类的InitInstance()成员函数和ExitInstance()成员函数中处理。因为MFC提供了DllMain()函数,因此,不需要手动编写此函数。DllMain()函数在DLL装载时,调用InitInstance()函数,在DLL卸载时,调用ExitInstance()函数。MFC常规DLL分为两种,分类标准是链接MFCDLL的方式。
静态链接MFC的规则DLL,在内部使用MFC,使用MFC的静态链接库生成DLL。
动态链接MFC的规则DLL,在内部使用MFC并动态链接到MFC。使用此方式的规则DLL,则必须在DLL的所有导出的函数的开头使用AFX_MANAGE_STATE宏,设置当前模块状态为DLL中的一个。
MFC常规DLL的创建
在VC 6.0中创建MFC常规DLL步骤如下:
(1)打开VC,选择File |New命令,弹出New对话框,选择其中的Projects选项卡,如图22-9所示。
图22-9 创建MFC常规DLL的第一步
(2)在Project Name文本框和Location文本框中填入相应的值,并选择MFC AppWizard(dll)图标。单击OK按钮,弹出MFC AppWizard-Step 1 of 1对话框,如图22-10所示。
(3)What type of DLL would youlike to create选项组中选择创建的DLL种类。其中,Regular DLL with MFC statically linked单选按钮表示创建静态链接到MFC的规则DLL;RegularDLL using shared MFC DLL单选按钮表示创建动态链接到MFC的规则DLL;MFC Extension DLL(using shared MFC DLL)单选按钮表示创建MFC扩展DLL。此处选择动态链接到MFC的规则DLL。其中,Automation复选框表示是否添加自动化支持,即可以在此工程中,直接运行其他程序。WindowsSockets复选框表示是否添加对Socket的支持。Wouldyou like to generate source file comments选项组表示是否为源文件生成注释。单击Finish按钮,弹出New Project Information对话框,如图22-11所示。
图22-10 创建MFC常规DLL的第二步
图22-11 创建MFC常规DLL的第三步
(4)单击OK按钮,这样就成功地创建了一个MFC常规DLL。
在创建了DLL后,就可以将程序功能添加到DLL中。
MFC常规DLL的创建实例
22.3.2小节介绍了创建MFC常规DLL的方法,本小节以一个实例讲解具体过程。在本小节实例实现的功能是创建一个通过MFC实现的对话框类,并在导出的接口函数中调用此对话框。具体过程为:
(1)按照22.3.2小节中介绍的方法,创建MFC常规DLL。
(2)在DLL工程中按照前面讲过的方法,添加一个对话框资源,并为此对话框资源创建派生自Cdialog类的对话框实例类,并在对话框内添加实现的功能。本实例中,实现单击对话框类中的按钮,则在静态框中显示欢迎词的功能。
(3)添加调用此对话框的接口函数。接口函数需要使用extern"C"__declspec(dllexport)修饰符指定,使其作为导出接口函数。代码如下:
1. extern "C" __declspec(dllexport) void ShowDlg(void) // 显示对话框
2. {
3. AFX_MANAGE_STATE(AfxGetStaticModuleState());
4. CdlgDllTest dlg; // 定义对话框变量
5. dlg.DoModal(); // 显示对话框
6. }
需要注意的是,此处在调用CdlgDllTest对话框前,需要调用AFX_MANAGE_STATE宏,此宏的功能是进行模块状态的切换,而AfxGetStaticModuleState()函数是在程序堆栈上创建一个AFX_MODULE_STATE类型的实例,以切换当前运行的模块状态。在动态链接MFC的常规DLL的每个接口函数中都需要调用此语句,或是在调用DLL的地方使用资源切换的方式(这种方式在第22.2节中介绍过)。不管哪种方式都需要进行运行程序状态切换,才可以完成对资源对话框的调用。
(4)添加完功能代码,编译链接DLL,生成RegMFCDLLSample.dll即可。
MFC常规DLL的调用
创建完MFC常规DLL后,就可以在应用程序中调用它了。MFC常规DLL既可以被MFC应用程序调用,也可以被非MFC应用程序调用。调用MFC常规DLL的方式有两种,一种是静态引用,通过加载静态链接库的lib文件实现。一种是动态引用,动态加载DLL后,获取要调用的函数地址,然后执行相应的函数。本节以动态加载的方式演示如何调用MFC常规DLL。代码如下:
1. void CRegMFCDllTestDlg::OnButtonInvokedll()
// 调用DLL
2. {
3. typedef void (*pFunction)(void);// 定义函数变量
4. HINSTANCE hLibrary; // DLL句柄
5. hLibrary = LoadLibrary("RegMFCDLLSample.dll");
// 装载DLL
6. if (hLibrary == NULL) MessageBox("DLL加载
失败"); // 提示错误信息
7. pFunction pShowDlg = (pFunction)GetProcAddress
(hLibrary,"ShowDlg");
8. // 执行函数
9. if (NULL==pShowDlg) MessageBox("DLL中不存在指
定的函数"); // 输出提示
10. else pShowDlg();
11. }
上面代码定义了函数指针变量pFunction。调用LoadLibrary()函数装载要执行的DLL,此处是RegMFCDLLSample.dll。如果加载成功,使用GetProcAddress()函数获取要执行的接口函数的地址,如果查找到函数,则执行。程序运行的效果如图22-12所示。
图22-12 MFC常规DLL调用实例运行效果图
MFC扩展DLL的创建与使用实例
MFC常规DLL是使用MFC但是导出的接口不支持MFC的DLL,而MFC扩展DLL则是内部既使用MFC,导出的接口也支持MFC的DLL,解决了要在DLL和EXE之间传递从MFC派生而来的类的问题。本节介绍MFC扩展DLL的创建和使用实例。
22.4.1 MFC扩展DLL的创建
MFC扩展DLL实现继承子MFC类库中的已经存在的类,完成可重复使用的类的DLL。扩展DLL使用MFC的动态链接版本,也就是MFC共享版本。只有使用MFC共享版本生成的MFC可执行文件(应用程序或规则DLL),可以使用扩展DLL。使用扩展DLL可以从MFC中继承新的自定义类,并为应用程序提供扩展的MFC版本。
DLL的客户端EXE必须是使用_AFXDLL编译的MFC应用程序。
动态链接到MFC的规则DLL也可以使用扩展DLL。
扩展DLL也可以使用_AFXEXT定义进行编译,强制定义_AFXDLL,并保证正确的特性。使得当生成DLL时,AFX_EXT_CLASS定义为__declspec(dllexport),如果在扩展DLL中使用宏声明类则是必需的。
扩展DLL不会实例化从CwinApp继承的类,但是依赖于客户端应用程序或DLL提供对象。
扩展DLL也提供一个DllMain()函数,并进行必需的初始化工作。
扩展DLL使用MFC的动态链接版本生成(也就是共享MFC版本)。只有使用共享版本MFC的MFC可执行程序(应用程序或规则DLL)才可以使用扩展DLL。无论是客户端应用程序还是扩展DLL,必须使用相同的MFC.DLL版本。
扩展DLL可以在应用程序和DLL之间传递派生自MFC的对象。在对象创建的模块中与传入对象相关的成员函数也会传入。因为当使用共享MFC的DLL版本时,这些函数被正确地导出,可以在应用程序和导入的扩展DLL之间自由地传递MFC或派生的MFC对象指针。
MFC扩展DLL使用共享版本的MFC与应用程序使用共享版本的DLL的方法是相同的,但是也有不同之处。
没有继承子CwinApp的派生类。必须与客户端应用程序的CwinApp派生对象一起工作。也就是说,客户端应用程序处理主消息队列、空闲队列等。
在DllMain()函数中调用AfxInitExtensionModule()函数,并检测此函数的返回值。如果此函数返回0,则从DllMain()函数中返回0。
如果扩展DLL想导出应用程序的CruntimeClass对象或资源,则会在初始化时,创建CdynLinkLibrary对象。
如果使用DEF文件导出,在头文件的开头和结尾处放置以下代码。
1. #undef AFX_DATA
2. #define AFX_DATA AFX_EXT_DATA
3. // 头文件体
4. #undef AFX_DATA
5. #define AFX_DATA
这4行可以保证扩展DLL中的代码正确编译。如果没有这4行,会导致DLL编译或链接不正确。创建MFC扩展DLL的方法与创建MFC常规DLL的步骤基本是相同的,只是在创建MFC DLL的第一步中,选择DLL的类型为MFC Extension DLL(using)shared MFC DLL选项,则创建的DLL就是MFC扩展DLL。
MFC扩展DLL的创建实例
22.4.1小节介绍了创建MFC扩展DLL的方法,本小节以一个实例讲解具体过程。在本小节实例实现的功能是创建一个通过MFC实现的对话框类,并在一个导出类中提供调用此对话框的接口函数。具体过程为:
(1)按照22.4.1小节中介绍的方法,创建MFC扩展DLL。
(2)在DLL工程中按照前面讲过的方法,添加一个对话框资源,并为此对话框资源创建派生自Cdialog类的对话框实例类。并在对话框内添加实现的功能,本实例中,实现单击对话框类中的按钮,在静态框中显示欢迎词。
(3)添加调用此对话框的接口类。接口类需要使用AFX_EXT_CLASS修饰符指定,使其作为导出类。代码如下:
1. class AFX_EXT_CLASS CExtDLLClass : Cobject
2. {
3. public:
4. void ShowDlg();
5. CExtDLLClass();
6. virtual ~CExtDLLClass();
7. };
其中,在ShowDlg()函数中会调用自定义的对话框CDlgExtDLL。而自定义对话框类CDlgExtDLL可以按照普通的对话框程序一样设计使用。
(4)添加完功能代码,编译链接DLL,生成ExtMFCDLLSample.cpp.dll即可。
MFC扩展DLL的调用
创建完MFC扩展DLL后,就可以在应用程序中调用它了。MFC扩展DLL既可以被MFC应用程序调用,也可以被非MFC应用程序调用。调用MFC扩展DLL的方式是通过静态引用,即通过加载静态链接库的lib文件实现。要完成对MFC扩展DLL的调用,需要3个资源。
包含要调用的类的头文件,在本例中是ExtDLLClass.h文件。
需要加载MFC扩展DLL对应的静态链接库LIB文件,在本例中是ExtMFCDLLSample.lib文件。
MFC扩展DLL的动态链接库,在本例中是ExtMFCDLLSample.dll文件。代码如下:
下面代码表示调用MFC扩展DLL中的接口类提供的对话框功能。
1. void CExtMFCDLLTestDlg::OnButtonInvokedlg() // 调用DLL中的对话框
2. {
3. CExtDLLClass dlg; // 定义对话框变量
4. dlg.ShowDlg(); // 显示对话框
5. }
从上面可以看出,在调用MFC扩展DLL的时候,调用方法与普通的MFC类调用的方式是相同的。在本例中,DLL导出的类是继承自MFC的Cobject类,同样也可以导出派生自MFC的其他类。程序运行效果如图22-13所示。
图22-13 调用MFC扩展DLL的运行效果图
DLL的查看与调试
Windows操作系统的核心功能是采用模块的方式实现的。它将各种相关功能放置在同一DLL模块中。因此,每个应用程序都会调用相关的系统的或用户自定义的DLL。因此,在编写程序时,就必须掌握DLL的查看和调试的方法。
22.5.1 使用Depends工具查看DLL接口
VC 6.0提供了查看DLL接口的工具--Depends。调用方法是选择"开始"|"所有程序"|"MicrosoftVisual Studio 6.0"|"Microsoft Visual Studio 6.0Tools"|"Depends"命令,即可打开Depends工具。要查看DLL接口,则选择"File"|"Open"命令,选择要查看的DLL文件,则界面中会显示DLL调用的DLL及其提供的接口,如图22-14所示。
图22-14 Depends工具运行界面图
在图22-14中,显示了在22.3中创建的DLL的接口。其中左边树形视图,显示了DLL调用的所有其他DLL的列表。右边列表部分显示了查看的DLL提供的接口函数。底部的列表视图显示了调用的DLL模块的信息。在左边树形视图中,选择相应的DLL,在右边的列表部分,会显示对应的接口函数的列表。其中,Ordinal列表示函数在DLL中的序号或名称,Hint列表示接口函数在DLL内部的序号值,Function列表示函数名称,Entry Point列表示函数入口点。从图22-15中可以看到,REGMFCDLLSAMPLE.DLL中提供了ShowDlg()接口函数。用户可以使用此工具查看指定DLL所调用的其他DLL和指定DLL提供的接口函数。
DLL的调试
在编写的程序,一定会遇到需要调试的情况。DLL的调试与EXE调试是类似的,但是在EXE调试时,可以直接在要调试的代码行上加上断点进行调试。当EXE调用DLL时,使用静态链接的方法调用DLL接口,则可以在DLL需要调试的源代码处设置断点,直接运行EXE程序,则程序运行到断点时,会中断以进行调试。但是如果动态加载在断点调试就比较困难。如果要专门调试某个DLL,则可以通过以下两种方式设置调试DLL的宿主程序。
(1)通过选择Project|Settings命令,弹出Project Settings对话框。选择Debug选项卡,在Executable for debug session文本框中选择要运行用于调试DLL的可执行文件,如图22-15所示。
(2)直接运行DLL工程,则会弹出Executable For Debug Session对话框。在Executablefile name文本框中选择要运行用于调试DLL的可执行文件,如图22-16所示。
设置好了宿主程序,在DLL源代码中要调试的代码行上加入断点,并运行宿主程序,则程序运行到DLL的断点处会中断等待进行调试。
除了加断点进行调试的方法外,其他的调试方法在DLL中与在EXE中进行调试的方法是一样的。熟练掌握程序调试的方法,可以加快程序的开发效率,并且可以提高代码质量。
图22-15 设置DLL调试的宿主程序
图22-16 运行设置DLL调试的宿主程序
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。