在做IE BHO插件dll的時候,需要打開一個模式對話框。當我添加了dialog資源,然後MyDialog dlg; dlg.DoModal();時,afxwin1.inl第23、26行出現斷言失敗:
_AFXWIN_INLINE HINSTANCE AFXAPI AfxGetInstanceHandle()
{ ASSERT(afxCurrentInstanceHandle != NULL);
return afxCurrentInstanceHandle; }
_AFXWIN_INLINE HINSTANCE AFXAPI AfxGetResourceHandle()
{ ASSERT(afxCurrentResourceHandle != NULL);
return afxCurrentResourceHandle; }
可以發現是afxCurrentInstanceHandle和afxCurrentResourceHandle這兩個爲NULL造成的。然後我想起來,dll中AfxGetInstanceHandle()方法默認返回的是.exe的資源訪問句柄。對此MSDN說明如下:
AfxGetInstanceHandle always returns the HINSTANCE of your executable file (.EXE) unless it is called from within a DLL linked with the USRDLL version of MFC. In this case, it returns an HINSTANCE to the DLL.
於是乎,我在MyDialog dlg; dlg.DoModal();之前加上
AFX_MANAGE_STATE(AfxGetAppModuleState());
心想着這下可以了吧?可是還是出現相同的問題。根據經驗,這是可以的啊。而且我的stdafx.h種已經包含了mfc的相關頭文件,比如:
//-----------------------------------------------------------------------------
#include <afxwin.h> //----- MFC core and standard components
#include <afxext.h> //----- MFC extensions
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxole.h> //----- MFC OLE classes
#include <afxodlgs.h> //----- MFC OLE dialog classes
#include <afxdisp.h> //----- MFC Automation classes
#endif //----- _AFX_NO_OLE_SUPPORT
檢查了DllMain()方法,原來沒有調用:
if (!AfxWinInit(hInstance, NULL, _T(""), 0))
{
AfxWinTerm();
return FALSE;
}
加上這個一切正常了,測試了一下AFX_MANAGE_STATE(AfxGetAppModuleState()); 也可以去掉。
看來,exe或者dll中加載資源時候,一定要注意切換資源所在的HINSTANCE,同時在atl com dll中使用MFC,一定要調用AfxWinInit()初始化相關參數。
附加幾點:
1. 查閱資源,發現原來AFX_MANAGE_STATE(AfxGetAppModuleState());的用法是這樣的:
如果從外面調用dll裏面發佈出來的方法,在該方法中加載資源,比如加載該dll定義的對話框資源,應該在其方法實現裏,最前面加上這句,使得dll之外調用時,自動的切換MFC資源加載的句柄,方法調用完後會自動恢復成原來的。
2. 在dialog.DoModal();的前後這樣嘗試動態的自己設置ResourceHandle,資源加載完後恢復也不行。
AFX_MANAGE_STATE(AfxGetAppModuleState()); //DllMain()中AfxWinInit()以後,這句可以省略。
HINSTANCE hExeIns = AfxGetInstanceHandle(); //不調用AfxWinInit(),此句人就報錯。
AfxSetResourceHandle((HINSTANCE)_Module.m_hInstResource);// 切換MFC加載資源從當前exe到當前dll資源實例
MyDialog dialog(AfxGetMainWnd());
dialog.DoModal();
AfxSetResourceHandle(hExeIns); // 將MFC資源加載切換回去。