我是靠谱客的博主 阳光电话,最近开发中收集的这篇文章主要介绍DLL详解(下)---MFC下的DLLMFC规则DLLMFC扩展DLL,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

  • MFC规则DLL
      • 何为规则DLL(Regular DLL)
      • MFC规则DLL的创建
    • 带静态链接MFC的规则的DLL
    • 使用共享MFC DLL的规则DLL
  • MFC扩展DLL

(本文针对的是使用MFC下的DLL)

MFC规则DLL

何为规则DLL(Regular DLL)

(1)该DLL是基于MFC的,可以在这种DLL内部使用MFC。
(2)该DLL是"规则"的,它不同于"MFC扩展DLL",在规则DLL中内部虽然是可以使用MFC,但是规则DLL的接口应该不能是基于MFC的。而MFC扩展DLL与应用程序接口可以是MFC,可以从MFC扩展dll中导出一个MFC的派生类。

Regular DLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。在这种动态连接库中,包含一个从CWinApp继承下来的类,DllMain函数则由MFC自动提供。

共享MFC DLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。EXE和DLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为 DLL的模块句柄;如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。(解释:EXE模块在进程虚拟空间中的起始地址 。 进程本身的模块句柄一般为0x400000 , 而DLL模块的缺省句柄为0x10000000 。 如果程序同时加载了多个DLL,则每个DLL模块都会有不同的 HINSTANCE 。 应用程序在加载DLL时对其进行了重定位。)

模块的切换有三种方式:

  1. 在DLL函数中调用AFX_MANAGE_STATE(AfxGetStaticModuleState());

    void ShowDlg(void)
    {
    	//在函数开始处变更,在函数结束时恢复
    	//将AFX_MANAGE_STATE(AfxGetStaticModuleState());
    	//作为接口函数的第一条语句进行模块状态切换
    	AFX_MANAGE_STATE(AfxGetStaticModuleState());
    	CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框
    	dlg.DoModal();
    
    }
    
  2. 在DLL函数中调用AfxGetResourceHandle();

    AfxGetResourceHandle用于获取当前资源模块句柄,而AfxSetResourceHandle则用于设置程序目前要使用的资源模块句柄。

    我们将DLL中的接口函数ShowDlg改为:

    void ShowDlg(void)   
    {   
        //方法2的状态变更   
         HINSTANCE save_hInstance = AfxGetResourceHandle();   
         AfxSetResourceHandle(theApp.m_hInstance);   
         CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框   
         dlg.DoModal();   
         //方法2的状态还原   
         AfxSetResourceHandle(save_hInstance);   
    }  
    

    ​ 通过AfxGetResourceHandleAfxSetResourceHandle的合理变更,我们能够灵活地设置程序的资源模块句柄,而方法一则只能在DLL接口函数退出的时候才会恢复模块句柄。方法二则不同,如果将ShowDlg改为:

    extern CSharedDllApp theApp; //需要声明theApp外部全局变量   
    void ShowDlg(void)   
    {   
        //方法2的状态变更   
        HINSTANCE save_hInstance = AfxGetResourceHandle();   
        AfxSetResourceHandle(theApp.m_hInstance);   
        CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框   
        dlg.DoModal();   
        //方法2的状态还原   
        AfxSetResourceHandle(save_hInstance);   
        //使用方法2后在此处再进行操作针对的将是应用程序的资源   
        CDialog dlg1(IDD_DLL_DIALOG); //打开ID为2000的对话框   
        dlg1.DoModal();   
    }   
    

    在应用程序主对话框的“调用DLL”按钮上点击,将看到两个对话框,相继为DLL中的对话框(图6)和EXE中的对话框(图7)。

  3. 由应用程序自身切换(不推荐,最麻烦)

    资源模块的切换除了可以由DLL接口函数完成以外,由应用程序自身也能完成。

    现在我们把DLL中的接口函数改为最简单的:

    void ShowDlg(void)   
    {   
        CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框   
        dlg.DoModal();   
    }   
    

    而将应用程序的OnCalldllButton函数改为:

    void CSharedDllCallDlg::OnCalldllButton()   
    {   
        //方法3:由应用程序本身进行状态切换   
        //获取EXE模块句柄   
        HINSTANCE exe_hInstance = GetModuleHandle(NULL);   
        //或者HINSTANCE exe_hInstance = AfxGetResourceHandle();   
        //获取DLL模块句柄   
        HINSTANCE dll_hInstance = GetModuleHandle("SharedDll.dll");   
        AfxSetResourceHandle(dll_hInstance); //切换状态   
        ShowDlg(); //此时显示的是DLL的对话框   
        AfxSetResourceHandle(exe_hInstance); //恢复状态   
        //资源模块恢复后再调用ShowDlg   
        ShowDlg(); //此时显示的是EXE的对话框   
    }  
    

    ​ 方法三中的Win32函数GetModuleHandle可以根据DLL的文件名获取DLL的模块句柄。如果需要得到EXE模块的句柄,则应调用带有Null参数的GetModuleHandle

    ​ 方法三与方法二的不同在于,方法三是在应用程序中利用AfxGetResourceHandleAfxSetResourceHandle进行资源模块句柄切换的。同样地,在应用程序主对话框的“调用DLL”按钮上点击,也将看到两个对话框,相继为DLL中的对话框和EXE中的对话框。

MFC规则DLL的创建

​ MFC规则DLL并不是MFC应用程序,它所继承自CWinApp的类不包含消息循环。这是因为,MFC规则DLL不包含CWinApp::Run机制,主消息泵仍然由应用程序拥有。如果DLL 生成无模式对话框或有自己的主框架窗口,则应用程序的主消息泵必须调用从DLL 导出的函数来调用PreTranslateMessage成员函数。

(内存泄漏的一种可能原因是MFC创建了在消息处理函数内部使用的临时对象。在MFC应用程序中,这些临时对象将CWinApp::OnIdle()在处理消息之间调用的函数中自动清除。但是,在MFC动态链接库(DLL)中,OnIdle()不会自动调用该函数。结果,临时对象不会自动清除。若要清除临时对象,DLL必须OnIdle(1)定期显式调用。)

在进程附加时,该_DllMainCRTStartup函数设置缓冲区安全性检查,初始化CRT和其他库,初始化运行时类型信息,初始化并调用静态和非本地数据的构造函数,初始化线程本地存储,为该线程增加一个内部静态计数器每个附件,然后调用用户或库提供的DllMain

因为常规MFC DLL具有一个CWinApp对象,所以它们应在与MFC应用程序相同的位置执行初始化和终止任务:在DLL 派生类的InitInstanceExitInstance成员函数中CWinApp。因为MFC提供了for 和DllMain调用的函数,所以您不应编写自己的函数。MFC提供的函数在加载DLL时调用,并且在DLL卸载之前调用。_DllMainCRTStartup``DLL_PROCESS_ATTACH``DLL_PROCESS_DETACH``DllMain``DllMain``InitInstance``ExitInstance

参考链接:https://blog.csdn.net/nupt123456789/article/details/7343820

带静态链接MFC的规则的DLL

静态链接到MFC的规则DLL与MFC库(包括MFC扩展 DLL)静态链接,将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时,MFC使用DLL的资源。因此,在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。这种DLL是使用MFC的静态链接库版本构建的。函数通常使用标准C接口从常规MFC DLL中导出。(将DLL的相关代码写进EXE)

功能:

  1. 客户端可执行文件可以用任何支持DLL使用的语言编写,它不必是MFC应用程序。
  2. DLL可以链接到应用程序使用的同一MFC静态链接库。DLL的静态链接库不再有单独的版本。
  3. 在MFC的4.0版之前,USRDLL提供的功能类型与静态链接到MFC的常规MFC DLL相同。从Visual C ++版本4.0开始,术语USRDLL已过时。

要求

  1. 此类DLL必须实例化从派生的类CWinApp
  2. 这种DLL使用DllMainMFC提供的。InitInstanceExitInstance普通MFC应用程序一样,将所有特定于DLL的初始化代码放在成员函数中,并将终止代码放在其中。
  3. 即使术语USRDLL已过时,您仍然必须在编译器命令行上定义“ _USRDLL ”。此定义确定从MFC头文件中提取哪些声明。

常规MFC DLL中的所有内存分配都应保留在DLL中;DLL不应传递给调用可执行文件或从其接收以下任何内容:

  • 指向MFC对象的指针
  • 指向由MFC分配的内存的指针

使用共享MFC DLL的规则DLL

打包时MFC的DLL的内容没有被包含在EXE文件中,运行时要求系统中要有相关的DLL文件。(MFC: Microsoft Foundation Classes 可以理解为是一个工具,它是在C++环境下编写应用程序的一个框架和引擎。)

在动态链接到MFC的常规MFC DLL中所有导出功能的开头添加宏AFX_MANAGE_STATE(但是不能在常规MFC的DLL静态链接到MFC或MFC扩展DLL使用。),以将当前模块状态设置为DLL的状态。这是通过将以下代码行添加到从DLL导出的函数的开头来完成的:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

动态链接到MFC的常规MFC DLL具有以下功能:

  • 这是Visual C ++ 4.0引入的新型DLL。
  • 客户端可执行文件可以用任何支持DLL使用的语言(C,C ++,Pascal,Visual Basic等)编写;它不必是MFC应用程序。
  • 与静态链接的常规MFC DLL不同,这种类型的DLL是动态链接到MFC DLL(也称为共享MFC DLL)的。
  • 链接到此类DLL的MFC导入库与MFC扩展DLL或使用MFC DLL的应用程序所使用的库相同:MFCxx(D).lib。

动态链接到MFC的常规MFC DLL具有以下要求:

  • 这些DLL使用定义的**_AFXDLL进行编译,就像动态链接到MFC DLL的可执行文件一样。但是也定义了_USRDLL**,就像静态链接到MFC的常规MFC DLL一样。
  • 这种类型的DLL必须实例化CWinApp派生的类。
  • 这种DLL使用DllMainMFC提供的。InitInstanceExitInstance普通MFC应用程序一样,将所有特定于DLL的初始化代码放在成员函数中,并将终止代码放在其中。

MFC扩展DLL

MFC扩展DLL的内涵为MFC的扩展,是使用MFC的动态链接库版本(也称为MFC的共享版本)构建的。只有使用MFC共享版本构建的MFC可执行文件(应用程序或常规MFC DLL)才可以使用MFC扩展DLL。

扩展DLL也可以用于在应用程序和DLL之间传递MFC派生的对象。与传递的对象关联的成员函数存在于创建对象的模块中。因为使用共享的DLL版本的MFC时这些函数已正确导出,所以您可以在应用程序与其加载的MFC扩展DLL之间自由传递MFC或MFC派生的对象指针。

MFC扩展DLL具有以下功能和要求:

  • 客户端可执行文件必须是使用_AFXDLL定义编译的MFC应用程序。
  • 动态链接到MFC的常规MFC DLL也可以使用MFC扩展DLL。
  • MFC扩展DLL应使用_AFXEXT定义进行编译。这_AFXDLL也要进行定义,并确保从MFC头文件中提取正确的声明。它还确保将AFX_EXT_CLASS其定义为__declspec(dllexport)在构建DLL时的定义,如果使用此宏在MFC扩展DLL中声明类,则这是必需的。
  • MFC扩展DLL不应实例化从派生的类CWinApp,而应依靠客户端应用程序(或DLL)来提供此对象。
  • 但是,MFC扩展DLL应该提供一个DllMain功能并在那里进行任何必要的初始化。

MFC扩展DLL使用MFC的共享版本的方式与应用程序使用MFC的共享DLL版本的方式相同,但还有一些其他注意事项:

  • 没有CWinApp派生的对象。它必须与CWinApp客户端应用程序的-derived对象一起使用。这意味着客户端应用程序拥有主消息泵,空闲循环等。
  • 它调用AfxInitExtensionModuleDllMain函数。应该检查该函数的返回值。如果从AfxInitExtensionModule返回零值,则从DllMain函数返回0 。
  • 如果MFC扩展DLL想要将对象或资源导出到应用程序,则它将在初始化期间创建CDynLinkLibrary对象CRuntimeClass

在MFC的4.0版之前,这种类型的DLL被称为AFXDLL。AFXDLL是指_AFXDLL在构建DLL时定义的预处理器符号。

(本文大部分都是参考了微软官方文档)


本文作者:"( ̄y▽, ̄)╭ "
本文链接:https://blog.csdn.net/weixin_42703404/article/details/106065436
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!


最后

以上就是阳光电话为你收集整理的DLL详解(下)---MFC下的DLLMFC规则DLLMFC扩展DLL的全部内容,希望文章能够帮你解决DLL详解(下)---MFC下的DLLMFC规则DLLMFC扩展DLL所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部