深入MFC扩展DLL
来源:互联网 发布:hexo 知乎图标 编辑:程序博客网 时间:2024/05/16 12:35
1 问题的引出
在创建一个使用MFC的DLL时,VS向导自动添加了一个从CwinApp继承而来的类,并重载了InitInstance和ExitInstance两个函数。在这个文件的前面还有一段注释:
//
//TODO: 如果此DLL 相对于MFC DLL 是动态链接的,
// 则从此DLL 导出的任何调入
// MFC 的函数必须将AFX_MANAGE_STATE 宏添加到
// 该函数的最前面。
//
// 例如:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // 此处为普通函数体
// }
//
// 此宏先于任何MFC 调用
// 出现在每个函数中十分重要。这意味着
// 它必须作为函数中的第一个语句
// 出现,甚至先于所有对象变量声明,
// 这是因为它们的构造函数可能生成MFC
// DLL 调用。
//
那么,AFX_MANAGE_STATE(AfxGetStaticModuleState());究竟是什么东西,为什么出现在每个函数中十分重要呢?
2 问题研究
我们知道,在MFC代码中,如果要访问一些模块中的资源或信息,通常要用AfxGetModuleState函数取得模块信息的指针,那么MFC又如何知道用户扩展的DLL中会有哪些资源呢?
看看AfxGetModuleState的实现:
PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afxBaseModuleState)
AFX_MODULE_STATE* AfxGetModuleState()
{
_AFX_THREAD_STATE* pState = _afxThreadState;
AFX_MODULE_STATE* pResult;
if (pState->m_pModuleState != NULL)
{
// thread state's module state serves as override
pResult = pState->m_pModuleState;
}
else
{
// otherwise, use global app state
pResult = _afxBaseModuleState.GetData();
}
ASSERT(pResult != NULL);
return pResult;
}
从这里可以看出,如果我们不修改_AFX_THREAD_STATE中的m_pModuleState指针,那么它将指向MFC DLL中的_afxBaseModuleState这个全局变量。但是在MFC运行时,它有时又必须访问MFC DLL中的资源,因此我们只能在每次要使用本模块资源之前修改此指针,在使用完成后又将此指针恢复。这就是AFX_MANAGE_STATE这个宏完成的工作。
再看看AfxGetStaticModuleState()做了什么。
LRESULT CALLBACK AfxWndProcDllStatic(HWND, UINT, WPARAM, LPARAM);
class _AFX_DLL_MODULE_STATE : public AFX_MODULE_STATE
{
public:
_AFX_DLL_MODULE_STATE() : AFX_MODULE_STATE(TRUE, AfxWndProcDllStatic, 7)
{ }
};
static _AFX_DLL_MODULE_STATE afxModuleState;
AFX_MODULE_STATE* AfxGetStaticModuleState()
{
AFX_MODULE_STATE* pModuleState = &afxModuleState;
return pModuleState;
}
进一步的分析发现AfxGetStaticModuleState()这个函数是和DllMain函数一样静态链接到DLL中的,也就是说每个DLL中都有一个独立的afxModuleState。我们知道AFX_MODULE_STATE中保存了每个模块的独立信息,如此模块中实现的类信息,此模块运行时使用的资源等等。据此我们就可以猜测AFX_MANAGE_STATE是用于将我们保存DLL信息的指针传递给MFC的。看看:
#define AFX_MANAGE_STATE(p) AFX_MAINTAIN_STATE2 _ctlState(p);
AFX_MODULE_STATE* AfxSetModuleState(AFX_MODULE_STATE* pNewState)
{
_AFX_THREAD_STATE* pState = _afxThreadState;
AFX_MODULE_STATE* pPrevState = pState->m_pModuleState;
pState->m_pModuleState = pNewState;
return pPrevState;
}
AFX_MAINTAIN_STATE::~AFX_MAINTAIN_STATE()
{
_AFX_THREAD_STATE* pState = _afxThreadState;
pState->m_pModuleState = m_pPrevModuleState;
}
AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pNewState)
{
m_pThreadState = _afxThreadState;
m_pPrevModuleState = m_pThreadState->m_pModuleState;
m_pThreadState->m_pModuleState = pNewState;
}
从以上代码可以看出,AFX_MANAGE_STATE可以保证在退出函数时恢复原来的ModuleState指针。
3 优缺点分析
毫无疑问的是,使用这种方式对于模块的独立性是很有帮助的,比如它可以保证在读取或者创建资源时优先使用本模块中的资源,而不用担心与其它模块中的资源ID相冲突。
但是缺点也是明显的,在每次调用MFC中的函数之前都必须使用AFX_MANAGE_STATE,非常的麻烦,而且有时候会出现一些比较难以发现的错误。比如将CImageList这种类型的变量放在自己的类中的时候,当类实例调用析构函数时,CImageList的析构函数也将释放它读取到的资源(句柄),但是这个时候往往没有使用AFX_MANAGE_STATE(因为CImageList是在析构函数调用完成后释放的),这样的话,这个ImageList句柄到CImageList指针的映射将无法正确释放,可能造成以后的隐患。
4 结论
1、只有当自己写的库是对MFC类库的扩展时才使用这种类型的DLL,否则使用普通DLL就行了。
2、如果扩展DLL没有使用独立的资源也不需要使用MFC扩展的DLL类型。
3、可以考虑将本DLL中的资源放在EXE或者其它类型的主程序中,从而避免使用此种类型的DLL。
4、如果是使用静态链接的DLL库,则无此问题。
- 深入MFC扩展DLL
- 深入MFC扩展DLL
- MFC--Extension DLL(扩展DLL)
- MFC--Extension DLL(扩展DLL)
- MFC扩展dll
- MFC扩展DLL编程
- MFC扩展DLL
- MFC扩展DLL 小结
- MFC扩展DLL
- MFC "扩展DLL" 制作
- ATL 调用MFC扩展dll
- MFC扩展DLL(转)
- 如何使用扩展MFC dll
- MFC程序调用MFC扩展DLL
- [MFC]MFC下的DLL编程——扩展DLL
- 静态.共享的规则MFC DLL/MFC扩展DLL详解
- 静态.共享的规则MFC DLL/MFC扩展DLL详解
- 静态、共享的规则MFC DLL,MFC扩展DLL详解
- Windows CE下操作GPIO的方法(以ARM9 S3C2410为例)
- 对url中的中文参数进行url编码
- s3c2410物理地址和虚拟地址空间
- Domino系统与AD的集成
- 怎样看编号了解显存信息
- 深入MFC扩展DLL
- jbpm的令牌
- 查询分析器远程单步调试存储过程的解决之道
- Timer和TimerTask详解
- ASP.NET 2.0中Gridview控件高级技巧
- jBPM-jpdl流程定义元素
- MVC用户认证web应用部分一
- Linux下各文件系统的比较
- (转)从C#里调用java程序