分析在MFC正规dll中使用资源的方法

源起

      自己创建了一个基于MFC动态链接的正规DLL。在该DLL中创建了一个字符串资源。结果当我使用CString::LoadString时却无法该字符串,而是空。

探索

      在使用该DLLexe工程中创建了同样的字符串资源。结果导出了EXE中资源定义的字符串。说明即使在DLL中,仍然使用了EXE中的资源而不是自身的资源。

解决方法

最简单的方法是使用静态链接MFCDLL

如果使用动态链接MFC可以有下面两种方法解决:

1.       在每个输出函数开始添加AFX_MANAGE_STATE(AfxGetStaticModuleState());

2.       在使用资源前使用HINSTANCE save_hInstance = AfxGetResourceHandle();

      AfxSetResourceHandle(theApp.m_hInstance);

      在使用资源后使用:AfxSetResourceHandle(save_hInstance);

原理

      下面说的都是针对MFC正规DLL,而且使用动态链接MFCDLL。这也是最常用的DLL类型。最后会讨论静态链接MFCMFC正规DLL

      MFC程序存在一个模块的概念。此的术语模块是指一个可执行程序,或指其操作不依赖于应用程序的其余部分但使用MFC运行库的共享副本的一个DLL(或一组DLL)。我们所创建的MFC DLL就是这种模块的一个典型实例。)

      每个模块都有一个模块状态,使用结构AFX_MODULE_STATE来表示。其中成员包括该模块的实例句柄(HINSTANCE m_hCurrentInstanceHandle;)、资源句柄(HINSTANCE m_hCurrentResourceHandle;)等。实例句柄表示了EXEDLL在进程虚拟空间的起始地址。资源句柄一般情况下和实例句柄相同,当寻找某个ID资源时就在该资源句柄对应的控件内搜索。在EXEDLL中,实例句柄和资源句柄都指向自身的装载地址。

      每个线程也都有一个线程状态,使用_AFX_THREAD_STATE表示。其中有成员指向当前活动模块的状态结构AFX_MODULE_STATE,即AFX_MODULE_STATE* m_pModuleState

      当我们在EXEDLL之间转换时,当前活动状态并不会改变。即,当调用DLL的输出函数时,在该函数执行期间,活动模块状态仍然是EXE的模块状态。为了改变当前活动状态,必须使用AFX_MANAGE_STATE(AfxGetStaticModuleState());,即前面所说的第一种方法。AfxGetStaticModuleState()函数很简单,就是返回当前所在模块的模块状态结构指针,对DLL而言就是DLL模块的状态指针。AFX_MANAGE_STATE会构造一个类,其构造函数中会把当前模块的状态指针赋值给线程状态结构的当前活动模块状态变量,并保保存之前的活动模块状态。。这样就使得当前活动模块状态等同于当前模块状态。在退出函数时,会调用类的析构函数,又会恢复之前的活动模块状态。

      上面讲的就是方法1的原理。通过这种方式,DLL函数使用DLL的模块状态,EXE使用EXE的模块状态。所以是理想的方法不会出现问题。

      方法2则不是很好。AfxSetResourceHandle是设置当前活动模块状态的资源句柄。当我们在DLL函数中调用AfxSetResourceHandle(theApp.m_hInstance);时,实际上是修改了EXE模块状态的资源句柄指向DLL模块的实例句柄。当然之后恢复不会出错,但对于并行程序而言可能出现不可预料的错误。

      对应使用MFC静态链接的DLL,则如果在DLL中,活动模块是DLL模块;在EXE中,活动模块是EXE。所以无需调用AFX_MANAGE_STATE,也保持了正常状态模块。而且即使调用AFX_MANAG_STATE,该语句也不会执行。

      另外,对应ATL生成的COM程序,则不必考虑这种问题。如果支持了MFC,无论是静态还是动态,当前活动模块都是当前模块。

相关知识点

1.       AfxGetResourceHandleAfxSetResourceHandleAfxGetInstanceHandle都是针对当前活动模块状态的。AfxGetStaticResourceHandle则是获得当前模块的句柄。

2.       实例句柄和资源句柄一般是一样的,但可以改变资源句柄,并不可以改变实例句柄。上文就改变了资源句柄。当使用纯资源dll时,开始就要设置该模块的资源句柄是纯资源DLL的实例句柄(即资源句柄)。

结论

      对应使用MFC动态链接的DLL,必须在每个导出函数前使用AFX_MANAGE_STATE(AfxGetStaticModuleState());。否则不仅资源会出错,还可能导致其它错误。而对于MFC静态链接的DLLATL产生的DLL,则完全可以忽略这种问题。

参考资料:

1.       DLL中使用资源(一,二),http://blog.csdn.net/rivershan/

2.       李久进的网上MFC教程,第九章。

3.       VC++ 技术内幕,第四版。但对其中的某些语句表示怀疑。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值