MFC DLL资源动态切换

在MFC使用过程中,遇到DLL资源与主EXE资源冲突问题。

出现这样的Bug,一时无从下手。

报错位置在核心代码中dlgcore.cpp。

[cpp] view plaincopy

  1. BOOL AFXAPI _AfxCheckDialogTemplate(LPCTSTR lpszResource, BOOL bInvisibleChild)  
  2. {  
  3.     ASSERT(lpszResource != NULL);  
  4.     HINSTANCE hInst = AfxFindResourceHandle(lpszResource, RT_DIALOG);  
  5.     HRSRC hResource = ::FindResource(hInst, lpszResource, RT_DIALOG);  
  6.     if (hResource == NULL)  
  7.     {  
  8.         if (DWORD_PTR(lpszResource) > 0xffff)  
  9.             TRACE(traceAppMsg, 0, _T("ERROR: Cannot find dialog template named '%s'.\n"),  
  10.                 lpszResource);  
  11.         else  
  12.             TRACE(traceAppMsg, 0, "ERROR: Cannot find dialog template with IDD 0x%04X.\n",  
  13.                 LOWORD((DWORD_PTR)lpszResource));  
  14.         return FALSE;  
  15.     }  
  16.           
  17.         ......  
  18.           
  19.         return TRUE;  
  20. }  

AfxFindResourceHandle查找资源文件时,本应在exe中的资源,结果返回了dll的句柄。

解决方法:

[cpp] view plaincopy

  1. //记录当前资源句柄  
  2. HINSTANCE hCurInstance = AfxGetResourceHandle();  
  3.   
  4. //设置主模块资源句柄  
  5. AfxSetResourceHandle(theApp.m_hInstance);  
  6.   
  7. Create(CTestDlg::IDD, GetDesktopWindow());  
  8. ShowWindow(SW_HIDE);  
  9. ShowWindow(SW_SHOWNOACTIVATE);  
  10.   
  11. //恢复当前模块句柄  
  12. AfxSetResourceHandle(hCurInstance);  

参照一篇文章,终于弄清楚了其中的来龙去脉。

文章来源: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 DLL
void CDLL::ShowDlg(void)
{
       CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框
       dlg.DoModal();
}
// in EXE
void CEXE::OnButtonClick()
{
       ShowDlg();
}

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

解释:

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

解决办法:

1、在DLL中改进:

方法1。

// 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);    
}

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

2、在应用程序中改进:

// 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资源、类或者需要创建窗口时。

时间: 2024-09-24 06:09:25

MFC DLL资源动态切换的相关文章

mdi toolbar动态切换-MFC 多文档程序 怎样 动态切换ToolBar

问题描述 MFC 多文档程序 怎样 动态切换ToolBar 我的应用场合是这样的: VS10创建的MDI 多文档程序,有2个文档模板,分别对应View1 和View2 两种视图,View1对应工具条ToolBar1 ,View2对应工具条Toolbar2. 我想实现:View1 激活时,显示ToolBar1: View2激活时,显示ToolBar2. 目前,我在CChildFrame中响应 WM____CHILDACTIVATE 消息,代码如下: void CChildFrame::OnChil

VC++.NET中定义和使用MFC DLL(一)

什么是DLL? DLL指的是动态链接库(Dynamic Link Library),它是一个可以被多个应用程序(甚至是不同语言编写的应用程序)同时调用的可执行二进制文件,是一个可共享的库.DLL是建立在客户/服务器通信的概念上,包含若干函数.类或资源的库文件,函数和数据被存储在一个DLL(服务器)上并由一个或多个客户导出而使用,这些客户可以是应用程序或者是其它的DLL. 在下面我们将通过一个具体的例子来说明如何利用VC.Net定义一个DLL文件,并且在VC.Net的应用程序中调用,这个例子的主要

Win32 DLL和MFC DLL 中封装对话框

现在最常看见的关于DLL的问题就是如何在DLL中使用对话框,这是一个很普遍的关于如何在DLL中使用资源的问题.这里我们从Win32   DLL和MFC   DLL两个方面来分析并解决这个问题.           1.Win32   DLL               在Win32   DLL中使用对话框很简单,你只需要在你的DLL中添加对话框资源,而且可以在对话框上面设置你所需要的控件.然后使用DialogBox或者CreateDialog这两个函数(或相同作用的其它函数)来创建对话框,并定义

静态.共享的规则MFC DLL/MFC扩展DLL详解

引言:在编写MFC程序的时候,通常需要编写dll库以供其他程序调用.关于MFC dll的相关知识很多很杂,这里特酷吧结合自己学习中遇到的问题专门整理了一些MFC dll的基础知识.本部分共上下两篇文章,本文为上篇,MFC DLL应用程序类型分为以下三种:(1)使用共享MFC DLL的规则DLL(2)带静态链接MFC的规则DLL(3)MFC扩展DLL下面重点解释一下这些DLL的含义区别:一,规则DLL首先谈谈所谓的"规则DLL":"规则DLL"是由"Regu

程序实现多国语言的动态切换解决方案

实现思想: 传统的做法是把所有的资源都放到动态库中,一种语言一个动态库,程序运行的时候通过加载不同的动态库来实现多语言功能.这样做的缺点是不能动态切换语言,如果更换语言后必须重新启动软件.当然,没有人会需要经常的切换语言玩儿,但是采用动态库的方法,如果程序需要修改资源的话,就要更新所有的动态库,这是一个非常枯燥而且容易出现疏漏的工作. 我的方法是把所有用到的字符串都放到文件中,一种语言一个文件,根据选择的语言到对应的文件中去加载字符串.这样不但可以动态切换语言,而且用户可以根据需要自己添加新的语

VC++动态链接库(DLL)非MFC DLL介绍

  4.1一个简单的DLL 第2节给出了以静态链接库方式提供add函数接口的方法,接下来我们来看看怎样用动态链接库实现一个同样功能的add函数. 如图6,在VC++中new一个Win32 Dynamic-Link Library工程dllTest(单击此处下载本工程附件).注意不要选择MFC AppWizard(dll),因为用MFC AppWizard(dll)建立的将是第5.6节要讲述的MFC 动态链接库. 图6 建立一个非MFC DLL 在建立的工程中添加lib.h及lib.cpp文件,源

国际化-spring mvc4 动态切换语言不起作用

问题描述 spring mvc4 动态切换语言不起作用 我利用 SPRING4 MVC配置了动态切换语言,但是在页上点击中文.英文切换的时候不起作用.请高手看看 <?xml version=""1.0"" encoding=""UTF-8""?><beans xmlns=""http://www.springframework.org/schema/beans"" xm

Android动态切换主题

软件换肤从功能上可以划分三种: 1) 软件内置多个皮肤,不可由用户增加或修改: 最低的自由度,软件实现相对于后两种最容易. 2) 官方提供皮肤供下载,用户可以使用下载的皮肤: 用户可选择下载自己喜欢的皮肤,有些玩家会破解皮肤的定制方法,自己做皮肤使用,或者传到网上给大家用. 参考:http://blog.csdn.net/zhyooo123/article/details/6697186 3) 官方提供皮肤制作工具或方法,用户可自制皮肤. 关于主题和样式: 就像style一样,主题依然在<sty

net 4 0-.net如何用cookies动态切换主题

问题描述 .net如何用cookies动态切换主题 我做了两个主题,一个绿色背景,一个红色背景,但一在网页上加载只显示绿色,多次切换主题后还是绿色,求指点,为什么就切换不到红色 public partial class _Default : System.Web.UI.Page { protected void Page_PreInit(object sender, EventArgs e) { if (Request.Cookies["Theme"] != null) this.Th