在MFC使用过程中,遇到DLL资源与主EXE资源冲突问题。
出现这样的Bug,一时无从下手。
报错位置在核心代码中dlgcore.cpp。
解决方法:
参照一篇文章,终于弄清楚了其中的来龙去脉。
文章来源:http://blog.sina.com.cn/s/blog_62bb83b10100jbdj.html。
AFX_MANAGE_STATE(AfxGetStaticModuleState())
先看一个例子:
1、创建一个动态链接到MFC DLL的规则DLL,其内部包含一个对话框资源。指定该对话框ID如下: #define IDD_DLL_DIALOG 2000
2、创建一个基于对话框的mfc应用程序,它包含两个对话框资源,IDD_UI_DIALOG和IDD_EXE_DIALOG。并将后者的ID指定如下: #define IDD_EXE_DIALOG 2000其中前者是这个应用程序的用户界面,单击上面的按钮,将弹出一个对话框。部分代码如下:// in DLLvoid CDLL::ShowDlg(void){ CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框 dlg.DoModal();}// in EXEvoid CEXE::OnButtonClick(){ ShowDlg();}3、单击按钮,弹出的不是期望的DLL中的对话框IDD_DLL_DIALOG,而是应用程序中的对话框IDD_EXE_DIALOG。
解决办法:1、在DLL中改进:
方法1。
// in DLLvoid 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 DLLvoid CDLL::ShowDlg(void){ HINSTANCE save_hInstance = AfxGetResourceHandle(); AfxSetResourceHandle(theApp.m_hInstance); CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框 dlg.DoModal(); AfxSetResourceHandle(save_hInstance); }
注:AfxGetResourceHandle:获取当前资源模块句柄;AfxSetResourceHandle:设置程序目前要使用的资源模块句柄。 同方法1比较,方法2能够灵活地设置程序的资源模块句柄,而方法1则只能在DLL接口函数退出的时候才会恢复模块句柄。
2、在应用程序中改进:
// in EXEvoid CEXE::OnButtonClick(){ HINSTANCE exe_hInstance = GetModuleHandle(NULL); HINSTANCE dll_hInstance = GetModuleHandle("SharedDll.dll"); AfxSetResourceHandle(dll_hInstance); //切换状态 ShowDlg(); AfxSetResourceHandle(exe_hInstance); //恢复状态}
注:使用状态切换的情况:当DLL导出函数包含MFC资源、类或者需要创建窗口时。