MFC资源冲突解决方法

AFX_MANAGE_STATE(AfxGetStaticModuleState())
 

先看一个例子:web

一、建立一个动态连接到MFC DLL的规则DLL,其内部包含一个对话框资源。指定该对话框ID以下:
              #define IDD_DLL_DIALOG 2000函数

二、建立一个基于对话框的mfc应用程序,它包含两个对话框资源,IDD_UI_DIALOG和IDD_EXE_DIALOG。并将后者的ID指定以下:
              #define IDD_EXE_DIALOG 2000
其中前者是这个应用程序的用户界面,单击上面的按钮,将弹出一个对话框。部分代码以下:
// in DLL
void CDLL::ShowDlg(void)
{
       CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框
       dlg.DoModal();
}
// in EXE
void CEXE::OnButtonClick()
{
       ShowDlg();
}

三、单击按钮,弹出的不是指望的DLL中的对话框IDD_DLL_DIALOG,而是应用程序中的对话框IDD_EXE_DIALOG。

解释:

一、应用程序进程自己及其调用的每一个DLL模块都具备一个全局惟一的HINSTANCE句柄,它们表明了EXE或DLL模块在进程虚拟空间中的起始地址。(进程自己的模块句柄通常为0x400000,而DLL模块的缺省句柄为0x10000000。若是程序同时加载了多个DLL,则每一个DLL模块都会有不一样的HINSTANCE。应用程序在加载DLL时对其进行了重定位)。
二、共享MFC DLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。EXE和DLL都有其本身的资源,并且这些资源的ID可能重复,若是应用程序与规则DLL共享MFC DLL(或MFC扩展DLL),那么将老是默认使用EXE的资源
三、所以应用程序须要经过资源模块的切换来找到正确的资源。若是应用程序须要来自于DLL的资源,就应将资源模块句柄指定为DLL的模块句柄;若是须要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。

解决办法:

一、在DLL中改进:spa

方法1。orm

// in DLL
void CDLL::ShowDlg(void)
{
       AFX_MANAGE_STATE(AfxGetStaticModuleState());
       CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框
       dlg.DoModal();
}对象

注:AFX_MANAGE_STATE(AfxGetStaticModuleState());必定是做为接口函数的第一条语句。
       其功能是在栈上(这意味着其做用域是局部的)建立一个AFX_MODULE_STATE类的实例,并将其指   针pModuleState返回。
       AFX_MODULE_STATE类利用其构造函数和析构函数进行存储模块状态现场及恢复现场的工做。
       该宏用于将pModuleState设置为当前的有效模块状态。当离开该宏的做用域时(也就离开了pModuleState所指栈上对象的做用域),先前的模块状态将由类AFX_MODULE_STATE的析构函数恢复。(即自动恢复)接口

方法2。进程

// in DLL
void CDLL::ShowDlg(void)
{
       HINSTANCE save_hInstance = AfxGetResourceHandle();
       AfxSetResourceHandle(theApp.m_hInstance);
       CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框
       dlg.DoModal();
       AfxSetResourceHandle(save_hInstance);    
}ci

注:AfxGetResourceHandle:获取当前资源模块句柄;AfxSetResourceHandle:设置程序目前要使用的资源模块句柄。
       同方法1比较,方法2可以灵活地设置程序的资源模块句柄,而方法1则只能在DLL接口函数退出的时候才会恢复模块句柄。资源

二、在应用程序中改进:作用域

// in EXE
void CEXE::OnButtonClick()
{
       HINSTANCE exe_hInstance = GetModuleHandle(NULL);
      HINSTANCE dll_hInstance = GetModuleHandle("SharedDll.dll");
      AfxSetResourceHandle(dll_hInstance); //切换状态
       ShowDlg();
      AfxSetResourceHandle(exe_hInstance); //恢复状态
}

注:使用状态切换的状况:当DLL导出函数包含MFC资源、类或者须要建立窗口时。

相关文章
相关标签/搜索