[MFC]关于Visual studio 2012的AfxGetMainWnd
在MSDN上对AfxGetMainWnd的解释是如果OLE服务器有一个对象在某个容器中激活且这个容器也是激活的(有点拗口),这个函数返回容纳激活文档的框架窗口对象。如果没有本地激活对象或者应用程序不是一个OLE的服务器,这个函数简单返回应用对象CWinApplication的m_pMainWnd。如果AfxGetMainWnd在主线程中调用得到的是应用程序的主窗口,如果是在第二个线程中调用的得到的是和这个线程关联的主窗口。
实际上并非这么简单,在一个动态加载的MFC常规DLL内部函数中调用这个函数可能会得到不同的结果,如果DLL中没有创建任何窗口,得到的会是主程序的主窗口,但是如果有创建窗口比如弹出一个模式对话框,在对话框的某个函数中调用AfxGetMainWnd就会得到这个对话框的窗口对象。具体的还是来看看这个函数是如何实现的吧。
_AFXWIN_INLINE CWnd* AFXAPI AfxGetMainWnd() { CWinThread* pThread = AfxGetThread(); return pThread != NULL ? pThread->GetMainWnd() : NULL; } CWinThread* AFXAPI AfxGetThread() { // check for current thread in module thread state AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); CWinThread* pThread = pState->m_pCurrentWinThread; return pThread; } AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState() { AFX_MODULE_THREAD_STATE* pResult=AfxGetModuleState()->m_thread.GetData(); ENSURE(pResult != NULL); return pResult; } CWnd* CWinThread::GetMainWnd() { if (m_pActiveWnd != NULL) return m_pActiveWnd; // probably in-place active // when not inplace active, just return main window if (m_pMainWnd != NULL) return m_pMainWnd; return CWnd::GetActiveWindow(); }
这里首先是取得当前的CWinThread对象,它是AFX_MODULE_THREAD_STATE的成员变量m_pCurrentWinThread,而AFX_MODULE_THREAD_STATE又是通过AfxGetModuleThreadState()函数得到的,它调用了AfxGetModuleState()函数,而说到AfxGetModuleState()我们必须讲到AFX_MANAGE_STATE(AfxGetStaticModuleState()),在DLL中导出一个函数时,这个函数的第一句我们一般都会调用AFX_MANAGE_STATE(AfxGetStaticModuleState()),它的作用就是切换模块相关的状态对象,这个状态对象包含了当前线程
CThreadLocal<AFX_MODULE_THREAD_STATE>、当前应用CWinApp等信息,这些信息都是保存在线程TLS中的。因此在进入DLL中我们可能使用AFX_MANAGE_STATE(AfxGetStaticModuleState())切换了模块状态,自然得到和主程序模块不同的CWinThread对象。
再来看CWinThread::GetMainWnd(),这和MSDN的解释差不多,如果有OLE激活对象返回激活窗口,没有就返回线程对象的主窗口,如果这个还为空,就获得当前应用程序的当前激活窗口,这个就实在说不定是那个窗口了,我们前面例子中说的DLL弹出模式对话框,自然就会得到这个模式对话框的窗口对象了,所以如果我们要在DLL中使用主程序框架窗口对象的化最好是从参数传入保存在DLL中吧。
关于MODULE STATE有很多的文章介绍了,比如这篇:http://hi.baidu.com/rootlife/blog/item/2f37e354ad8cdc5bd10906be.html,讲得还是比较清楚的。