MFC做到了从C/SDK开发Win32程序到利用OOP思想开发Win32程序的过渡,它的封装完美体现的C++的三大特性,提高了Win32程序的开发效率,但它的封装也使得本来清晰的脉络,变得晦涩起来。
今天我们探究被微软冠以Afx前缀的全局函数AfxGetApp(),这个函数作用是获取当前应用进程的指针,确切的说是获取由CWinApp派生出类的对象,相信懂MFC的人都熟知,但作为全局函数的它是如何在基类获取的派生类对象的?
现在我们开始一步一步揭开AfxGetApp()神秘面纱~
(1)AfxGetApp()
函数的声明在AFXWIN.H,定义在AFXWIN1.INL
_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
{ return afxCurrentWinApp; }
afxCurrentWinApp是一个宏,定义在AFXWIN.H中
#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp
(2)AfxGetModuleState()
其返回值为AFX_MODULE_STATE类指针,声明在AFXSTAT_.H
AFX_MODULE_STATE* AFXAPI AfxGetModuleState();
定义在AFXSTATE.CPP
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; }
AfxGetModuleState函数的定义中,可以看出函数返回的是pState->m_pModuleState或者_afxBaseModuleState.GetData();
(3)_afxThreadState,和_afxBaseModuleState都是全局变量,上文中的pState就是_afxThreadState.
_afxThreadState声明在AFXSTAT_.H,
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;//上面的pState->m_pModuleState就是这个值,存储模块状态 AFX_MODULE_STATE* m_pPrevModuleState; // memory safety pool for temp maps void* m_pSafetyPoolBuffer; // current buffer // thread local exception context AFX_EXCEPTION_CONTEXT m_exceptionContext; // CWnd create, gray dialog hook, and other hook data CWnd* m_pWndInit; CWnd* m_pAlternateWndInit; // special case commdlg hooking DWORD m_dwPropStyle; DWORD m_dwPropExStyle; HWND m_hWndInit; BOOL m_bDlgCreate; HHOOK m_hHookOldCbtFilter; HHOOK m_hHookOldMsgFilter; // other CWnd modal data MSG m_lastSentMsg; // see CWnd::WindowProc HWND m_hTrackingWindow; // see CWnd::TrackPopupMenu HMENU m_hTrackingMenu; TCHAR m_szTempClassName[96]; // see AfxRegisterWndClass HWND m_hLockoutNotifyWindow; // see CWnd::OnCommand BOOL m_bInMsgFilter; // other framework modal data CView* m_pRoutingView; // see CCmdTarget::GetRoutingView CFrameWnd* m_pRoutingFrame; // see CCmdTarget::GetRoutingFrame // MFC/DB thread-local data BOOL m_bWaitForDataSource; // common controls thread state CToolTipCtrl* m_pToolTip; CWnd* m_pLastHit; // last window to own tooltip int m_nLastHit; // last hittest code TOOLINFO m_lastInfo; // last TOOLINFO structure int m_nLastStatus; // last flyby status message CControlBar* m_pLastStatus; // last flyby status control bar // OLE control thread-local data CWnd* m_pWndPark; // "parking space" window long m_nCtrlRef; // reference count on parking window BOOL m_bNeedTerm; // TRUE if OleUninitialize needs to be called }; EXTERN_THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)//_afxThreadState全局变量声明
定义在AFXSTATE.CPP
THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)//_afxThreadState全局变量定义
_afxBaseModuleState声明定义在AFXSTATE.CPP
class _AFX_BASE_MODULE_STATE : public AFX_MODULE_STATE { public: #ifdef _AFXDLL _AFX_BASE_MODULE_STATE() : AFX_MODULE_STATE(TRUE, AfxWndProcBase, _MFC_VER) #else _AFX_BASE_MODULE_STATE() : AFX_MODULE_STATE(TRUE) #endif { } }; PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afxBaseModuleState)//_afxBaseModuleState全局变量声明定义
(4)AFX_MODULE_STATE类
我们看看AFX_MODULE_STATE类中有什么?其实它包含了AfxGetApp要返回的CWinApp。
// AFX_MODULE_STATE (global data for a module)
class AFX_MODULE_STATE : public CNoTrackObject
{
public:
#ifdef _AFXDLL
AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion);
AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,
BOOL bSystem);
#else
AFX_MODULE_STATE(BOOL bDLL);
#endif
~AFX_MODULE_STATE();
CWinApp* m_pCurrentWinApp;//转了好几次,终于见到庐山真面目了,没错,这就是我们从AfxGetApp获取的值。
HINSTANCE m_hCurrentInstanceHandle;
HINSTANCE m_hCurrentResourceHandle;
LPCTSTR m_lpszCurrentAppName;
BYTE m_bDLL; // TRUE if module is a DLL, FALSE if it is an EXE
BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not
BYTE m_bReserved[2]; // padding
DWORD m_fRegisteredClasses; // flags for registered window classes
// runtime class data
#ifdef _AFXDLL
CRuntimeClass* m_pClassInit;
#endif
CTypedSimpleList<CRuntimeClass*> m_classList;
// OLE object factories
#ifndef _AFX_NO_OLE_SUPPORT
#ifdef _AFXDLL
COleObjectFactory* m_pFactoryInit;
#endif
CTypedSimpleList<COleObjectFactory*> m_factoryList;
#endif
// number of locked OLE objects
long m_nObjectCount;
BOOL m_bUserCtrl;
// AfxRegisterClass and AfxRegisterWndClass data
TCHAR m_szUnregisterList[4096];
#ifdef _AFXDLL
WNDPROC m_pfnAfxWndProc;
DWORD m_dwVersion; // version that module linked against
#endif
// variables related to a given process in a module
// (used to be AFX_MODULE_PROCESS_STATE)
#ifdef _AFX_OLD_EXCEPTIONS
// exceptions
AFX_TERM_PROC m_pfnTerminate;
#endif
void (PASCAL *m_pfnFilterToolTipMessage)(MSG*, CWnd*);
#ifdef _AFXDLL
// CDynLinkLibrary objects (for resource chain)
CTypedSimpleList<CDynLinkLibrary*> m_libraryList;
// special case for MFCxxLOC.DLL (localized MFC resources)
HINSTANCE m_appLangDLL;
#endif
#ifndef _AFX_NO_OCC_SUPPORT
// OLE control container manager
COccManager* m_pOccManager;
// locked OLE controls
CTypedSimpleList<COleControlLock*> m_lockList;
#endif
#ifndef _AFX_NO_DAO_SUPPORT
_AFX_DAO_STATE* m_pDaoState;
#endif
#ifndef _AFX_NO_OLE_SUPPORT
// Type library caches
CTypeLibCache m_typeLibCache;
CTypeLibCacheMap* m_pTypeLibCacheMap;
#endif
// define thread local portions of module state
THREAD_LOCAL(AFX_MODULE_THREAD_STATE, m_thread)
};
(5)CWinApp构造函数
CWinApp* m_pCurrentWinApp;已经找到,那么它是在被赋值的呢,就是在CWinApp的构造函数,当MFC程序中CWinApp所派生的CMYWinApp(举例)类对象theApp(全局对象)被构造时,就会触动CWinApp构造函数,此时CWinApp构造函数中的this就指的是theApp,然后将this保存到m_pCurrentWinApp中。
CWinApp::CWinApp(LPCTSTR lpszAppName) { if (lpszAppName != NULL) m_pszAppName = _tcsdup(lpszAppName); else m_pszAppName = NULL; // initialize CWinThread state AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();//获取全局对象指针 AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread; ASSERT(AfxGetThread() == NULL); pThreadState->m_pCurrentWinThread = this; ASSERT(AfxGetThread() == this); m_hThread = ::GetCurrentThread(); m_nThreadID = ::GetCurrentThreadId(); // initialize CWinApp state ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please pModuleState->m_pCurrentWinApp = this;//此处就是将theApp的地址保存到m_pCurrentWinApp中 ASSERT(AfxGetApp() == this); // in non-running state until WinMain m_hInstance = NULL; m_pszHelpFilePath = NULL; m_pszProfileName = NULL; m_pszRegistryKey = NULL; m_pszExeName = NULL; m_pRecentFileList = NULL; m_pDocManager = NULL; m_atomApp = m_atomSystemTopic = NULL; m_lpCmdLine = NULL; m_pCmdInfo = NULL; // initialize wait cursor state m_nWaitCursorCount = 0; m_hcurWaitCursorRestore = NULL; // initialize current printer state m_hDevMode = NULL; m_hDevNames = NULL; m_nNumPreviewPages = 0; // not specified (defaults to 1) // initialize DAO state m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called // other initialization m_bHelpMode = FALSE; m_nSafetyPoolSize = 512; // default size }
到目前估计大家也明白了AfxGetApp()函数实现,欢迎探讨