当前位置:   article > 正文

MFC常规DLL的创建与使用实例_创建mfc dll 串口通信

创建mfc dll 串口通信

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所示。

http://images.51cto.com/files/uploadimg/20100804/164653280.jpg

图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所示。

http://images.51cto.com/files/uploadimg/20100804/164739100.jpg

图22-10  创建MFC常规DLL的第二步

 

http://images.51cto.com/files/uploadimg/20100804/164800870.jpg

图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所示。

http://images.51cto.com/files/uploadimg/20100804/165156808.jpg

图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所示。

http://images.51cto.com/files/uploadimg/20100804/1701410.jpg

图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所示。

http://images.51cto.com/files/uploadimg/20100804/170516423.jpg

图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中进行调试的方法是一样的。熟练掌握程序调试的方法,可以加快程序的开发效率,并且可以提高代码质量。

http://images.51cto.com/files/uploadimg/20100804/170822916.jpg

图22-15  设置DLL调试的宿主程序

 

http://images.51cto.com/files/uploadimg/20100804/170835548.jpg

图22-16  运行设置DLL调试的宿主程序

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/690562
推荐阅读
相关标签
  

闽ICP备14008679号