从win32到MFC(二)CWinApp


上一篇文章《从win32到MFC(一)前言》介绍了MFC的入口函数,有一段代码:

CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();

初次读到这两行代码还是比较混乱,可以推断AfxGetThread()和AfxGetApp()获得的CWinThread和CWinApp对象已经在入口函数执行前完成了构造。

写过MFC程序的开发者应该可以联想到全局变量 CxxxApp theApp,把AfxGetApp()与全局变量 theApp关联起来,AfxGetApp()获取的正是这个对象。

CWinApp的构造:

CWinApp::CWinApp(LPCTSTR lpszAppName)
{
    ......
    // 初始化 CWinThread 状态
    AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
    ENSURE(pModuleState);
    AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
    ENSURE(pThreadState);
    ASSERT(AfxGetThread() == NULL);
    pThreadState->m_pCurrentWinThread = this;
    ASSERT(AfxGetThread() == this);
    m_hThread = ::GetCurrentThread();
    m_nThreadID = ::GetCurrentThreadId();

    // 初始化 CWinApp 状态
    ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
    pModuleState->m_pCurrentWinApp = this;
    ASSERT(AfxGetApp() == this);
    ......
}

AfxGetThread 和 AfxGetApp 的实现:

CWinThread* AFXAPI AfxGetThread()
{
    AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
    CWinThread* pThread = pState->m_pCurrentWinThread;
    return pThread;
}
_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
    { return afxCurrentWinApp; }

#define afxCurrentWinApp    AfxGetModuleState()->m_pCurrentWinApp

通过以上代码的实现,可以清晰的看到 AfxGetThread 和 AfxGetApp 获得的指针对象保存在 AFX_MODULE_THREAD_STATE中,由CWinApp在构造函数中初始化。CWinApp继承自CWinThread,AfxGetThread 和 AfxGetApp 得到的其实是同一个对象。

以上代码的分析其实只考虑了主线程的情况,事实上在多线程的环境中其他线程执行 AfxGetThread 获取到的并不是CWinApp,而是当前线程的对象,继续往下分析 AfxGetModuleThreadState。

AfxGetModuleThreadState的实现:

AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState()
{
    AFX_MODULE_THREAD_STATE* pResult=AfxGetModuleState()->m_thread.GetData();
    ENSURE(pResult != NULL);
    return pResult;
}

AfxGetModuleThreadState 进一步调用 AfxGetModuleState 获取 AFX_MODULE_THREAD_STATE 指针对象。

AfxGetModuleState的实现:

AFX_MODULE_STATE* AFXAPI AfxGetModuleState()
{
    _AFX_THREAD_STATE* pState = _afxThreadState;
    ENSURE(pState);
    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();
    }
    ENSURE(pResult != NULL);
    return pResult;
}

AfxGetModuleState 的实现也很简洁,我们继续往下分析全局对象 _afxThreadState (在afxstate.cpp 143行)

THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)

#define THREAD_LOCAL(class_name, ident_name) \
 AFX_COMDAT CThreadLocal<class_name> ident_name;

THREAD_LOCAL宏定义展开其实是一个模板类的定义 CThreadLocal。

template<class TYPE>
class CThreadLocal : public CThreadLocalObject
{
// Attributes
public:
    AFX_INLINE TYPE* GetData()
    {
        TYPE* pData = (TYPE*)CThreadLocalObject::GetData(&CreateObject);
        ENSURE(pData != NULL);
        return pData;
    }
    AFX_INLINE TYPE* GetDataNA()
    {
        TYPE* pData = (TYPE*)CThreadLocalObject::GetDataNA();
        return pData;
    }
    AFX_INLINE operator TYPE*()
    { 
        return GetData(); 
    }
    AFX_INLINE TYPE* operator->()
    { 
        return GetData(); 
    }

// Implementation
public:
    static CNoTrackObject* AFXAPI CreateObject()
        { return new TYPE; }
};

可以看到 CThreadLocal 重载了 operator ->,最终调用了基类 CThreadLocalObject 的函数 GetData 来获取 _AFX_THREAD_STATE,阅读到这里终于快搞清 CWinThread 的真面目,我们继续往下分析。

CThreadLocalObject::GetData 的实现:

CNoTrackObject* CThreadLocalObject::GetData(
    CNoTrackObject* (AFXAPI* pfnCreateObject)())
{
    ENSURE(pfnCreateObject);
    
// 初次调用先构造 CThreadSlotData
if (m_nSlot == 0) { if (_afxThreadData == NULL) { _afxThreadData = new(__afxThreadData) CThreadSlotData; ENSURE(_afxThreadData != NULL); } m_nSlot = _afxThreadData->AllocSlot(); ENSURE(m_nSlot != 0); } CNoTrackObject* pValue = static_cast<CNoTrackObject*>(_afxThreadData->GetThreadValue(m_nSlot)); if (pValue == NULL) { // allocate zero-init object pValue = (*pfnCreateObject)(); // set tls data to newly created object _afxThreadData->SetValue(m_nSlot, pValue); ASSERT(_afxThreadData->GetThreadValue(m_nSlot) == pValue); } return pValue; }

最终通过 afxThreadData 来获取对象,Windows开发者应该对TLS(线程局部存储)的概念并不陌生,第一次读到这里想到了MFC应该通过 TLS 存储线程相关的环境上下文。

感兴趣的读者可以自行阅读类 CThreadSlotData 的实现细节,这里不再详细分析。

总结:

贴了这么多代码,简单的总结下流程:

AfxGetApp / AfxGetThread -> AfxGetModuleThreadState -> AfxGetModuleState -> CThreadLocalObject::GetData (_afxThreadState operator->) -> CThreadSlotData::GetThreadValue

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM