[转]如何在工作线程中创建窗口?

在前面我们研究了使用AFX_MANAGE_STATE(AfxGetStaticModuleState())进行DLL间的资源切换,以及工作线程中创建Windows消息循环的原理,以为就可以搞定一切类似问题了…但是请看以下代码



DWORD CTestMFCDlg::ThreadFunc(PVOID yy)

{

CAboutDlg dlg;

dlg.DoModal();

return 0;

}


void CTestMFCDlg::OnOK()

{

::CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,NULL,NULL);

}



在VC++6.0上编译运行出现以下ASSERT。


void CWnd::AssertValid() const

{

……

CHandleMap* pMap = afxMapHWND();

……


CObject* p;

ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||

(p = pMap->LookupTemporary(m_hWnd)) != NULL);

ASSERT((CWnd*)p == this);   // must be us


MFC有一个全局的Hash表(通过afxMapHWND()获得),用于把HWND句柄与MFC的封装对象CWnd进行关联,这样就可以通过CWnd::FromHandle()等函数把CWnd对象Attach到一个已有的HWND句柄上,利用MFC的封装函数可以简化对HWND的直接操作。很显然,这里的Assert是因为CWnd对象根据自身的窗口句柄(m_hWnd)从Hash表里找到CWnd对象指针与对象的本身(this)并不相同!这说明,CWnd对象创建时注册到的Hash表与目前检索的Hash表并不是同一个。为什么会是这样的呢?


CHandleMap* PASCAL afxMapHWND(BOOL bCreate)

{

AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();

if (pState->m_pmapHWND == NULL && bCreate)

{

…….

pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd),offsetof(CWnd, m_hWnd));

……

}


return pState->m_pmapHWND;



看来这个Hash表跟AfxGetModuleThreadState()有关,继续



AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState()

{

return AfxGetModuleState()->m_thread.GetData();

}




AFX_MODULE_STATE* AFXAPI 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;


}




那么_afxThreadState是什么呢?




EXTERN_THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)




class _AFX_THREAD_STATE : public CNoTrackObject


{


public:


_AFX_THREAD_STATE();


virtual ~_AFX_THREAD_STATE();




// override for m_pModuleState in _AFX_APP_STATE


AFX_MODULE_STATE* m_pModuleState;


AFX_MODULE_STATE* m_pPrevModuleState;




#define THREAD_LOCAL(class_name, ident_name)


AFX_DATADEF CThreadLocal<class_name> ident_name;


#define EXTERN_THREAD_LOCAL(class_name, ident_name)


extern AFX_DATA THREAD_LOCAL(class_name, ident_name)




分析的结果是 extern CThreadLocal<_AFX_THREAD_STATE> _afxThreadState。




template<class TYPE>


class CThreadLocal : public CThreadLocalObject


{


AFX_INLINE TYPE* GetData()


{


TYPE* pData = (TYPE*)CThreadLocalObject::GetData(&CreateObject);


ASSERT(pData != NULL);


return pData;


}


AFX_INLINE operator TYPE*()


{ return GetData(); }


AFX_INLINE TYPE* operator->()


{ return GetData(); }




static CNoTrackObject* AFXAPI CreateObject()


{ return new TYPE; }






可以看出来了,_afxThreadState是一个全局的对象。通过该对象可以获得_AFX_THREAD_STATE对象,后者是线程相关的。CThreadLocalObject的代码不再分析,大概就是检查当前的线程私有数据,如果有则返回,否则创建新的对象(即_AFX_THREAD_STATE)。




继续看AfxGetModuleState(),大致的意思是获取与当前线程相关联的AFX_MODULE_STATE对象,如果没有则获取该进程的缺省AFX_MODULE_STATE对象。




PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afxBaseModuleState)




class _AFX_BASE_MODULE_STATE : public AFX_MODULE_STATE




#define PROCESS_LOCAL(class_name, ident_name)


AFX_DATADEF CProcessLocal<class_name> ident_name;


#define EXTERN_PROCESS_LOCAL(class_name, ident_name)


extern AFX_DATA PROCESS_LOCAL(class_name, ident_name)




继续看AfxGetModuleThreadState(),在获得了AFX_MODULE_STATE对象之后,访问其m_thread成员。这又是一个线程相关的数据,可以获得AFX_MODULE_STATE在不同线程中的私有数据。




// AFX_MODULE_STATE (global data for a module)


class AFX_MODULE_STATE : public CNoTrackObject


{


// define thread local portions of module state


THREAD_LOCAL(AFX_MODULE_THREAD_STATE, m_thread)




现在简单总结一下,AfxGetModuleState()可以获得与执行线程关联的AFX_MODULE_STATE,而AfxGetModuleThreadState()可以获得与执行线程关联的AFX_MODULE_STATE与当前执行线程关联的AFX_MODULE_THREAD_STATE。看起来有点绕,再