最近寫一個程序,是在DLL裡面create一個FrameWnd,搞了一個星期,弄的焦頭爛額,最後才發現少加一條語句
AFX_MANAGE_STATE(AfxGetStaticModuleState()),現在把從網上轉的技術文檔記錄下來,備忘。
(轉)AFX_MANAGE_STATE(AfxGetStaticModuleState())
以前寫MFC的DLL的時候,總會在自動生成的代碼框架裡看到提示,需要在每一個輸出的函數開始添加上AFX_MANAGE_STATE (AfxGetStaticModuleState())。一直不明白這樣做的含義,也一直沒有這樣做,而且代碼也工作得好好的,所以感覺這好像一句廢 話。
最近的項目中,需要在DLL裡使用MFC生成界面,這才發現一旦資源放在不同的動態庫裡,而且還和多線程攪和在一起的時候,事情就變 得異常的復雜,以前對MFC的一知半解已經不足與應付了。程序莫名的崩潰,莫名的ASSERT,資源怎樣也裝載不起來,為什麼呢?每次,總是嘗試著,在每 一個線程的開始,把AFX_MANAGE_STATE(AfxGetStaticModuleState())添加上去,或者在某些地方用 AfxSetResourceHandler()一把,然後問題就解決了,但是不是很明白到底是怎麼回事,總感覺這種解決辦法讓人很不安心,仿佛在下一秒 問題又會突然冒出來。
前天,這個問題終於發揮到了極致,任我花費了好幾個小時,怎樣的嘗試都不能成功,在項目的關鍵時候發生這種事情,讓我暗暗發誓以後再也不用MFC了。正像很多的電影情節一樣,事情最後還是得到了解決,這次我決定不能再這麼算了,一定要把這個事情理解得明明白白。
在這裡,我遇到的問題就是,如何讓DLL裡的界面代碼使用該DLL的資源(Resource),如何在工作線程裡加載有IE控件的對話框?
我問同事,他們是如何實現DLL資源切換的?AFX_MANAGE_STATE(AfxGetStaticModuleState())這就是他們的答案,一如微軟的推薦,原來就是這麼簡單啊!讓我們來看看,這句代碼到底做了什麼?
#define AFX_MANAGE_STATE(p) AFX_MAINTAIN_STATE2 _ctlState(p);
AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pNewState)
{
m_pThreadState = _afxThreadState;
m_pPrevModuleState = m_pThreadState->m_pModuleState;
m_pThreadState->m_pModuleState = pNewState;
}
_AFXWIN_INLINE AFX_MAINTAIN_STATE2::~AFX_MAINTAIN_STATE2()
{ m_pThreadState->m_pModuleState = m_pPrevModuleState; }
原來,就是定義一個局部的對象,利用其構造和析構函數在函數的入口和函數的出口進行State狀態的切換,我猜AfxGetStaticModuleState()一定是獲取當前代碼所在DLL的State。
果然,請看
static _AFX_DLL_MODULE_STATE afxModuleState;
AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState()
{
AFX_MODULE_STATE* pModuleState = &afxModuleState;
return pModuleState;
}
class _AFX_DLL_MODULE_STATE : public AFX_MODULE_STATE
// AFX_MODULE_STATE (global data for a module)
class AFX_MODULE_STATE : public CNoTrackObject
{
...
CWinApp* m_pCurrentWinApp;
HINSTANCE m_hCurrentInstanceHandle;
HINSTANCE m_hCurrentResourceHandle;