MFC全局函數開局――AfxGetApp解剖
MFC中有不少的全局函數,方便在不同對象中獲取不同的內容或創建不同的對象。主要全局函數有:
AfxWinInit() AfxBeginThread() AfxEndThread() AfxFormatString1() AfxFormatString2()
AfxMessageBox() AfxOutPutDebugString() AfxGetApp() AfxGetMainWnd() AfxGetInstance()
AfxRegisterClass()
這些函數從名稱上可見豹斑(功能)。
本文是學習深入淺出MFC后的第一個筆記,解析AfxGetApp()函數
在AFXWIN.H中是這么定義的:
CWinApp* AFXAPI AfxGetApp();
那么AfxGetApp是怎么獲取當前App的CWinApp類指針呢?
AfxGetApp是一個內聯函數,其實現如下(在AFXWIN1.INL):
_AFXWIN_INLINE CWinApp *AFXAPI AfxGetApp()
{ return afxCurrentWinApp;}
而afxCurrentWinApp是一個宏,定義在AFXWIN.H中:
#define afxCurrentWinApp AfxGetModuleState()->m_pCurrentWinApp
AfxGetModuleState返回的是一個:AFX_MODULE_STATE類的指針(AFXSTAT_.H):
AFX_MODULE_STATE* AFXAPI AfxGetModuleState();
在AFX_MODULE_STATE類中定義了如下的成員變量:
CWinApp* m_pCurrentWinApp;
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
轉了這么多,自己都迷糊了,AFX_MODULE_STATE什么時候被初始化了,AfxGetModuleState又都干了些什么,不然怎么可 能調用AfxGetModuleState()->m_pCurrentWinApp獲得當前窗口的App呢?最有可能被初始化的地方是在構造函數 之中。而我們獲取的是App類型的指針,而App是繼承之CWinApp類的。因此下面我們看看CWinApp構造函數做了些什么工作:
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; //又將this指針傳給了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
}
CWinApp的構造函數申明了一個AFX_MODULE_STATE類的指針,里面通過this指針填充了AFX_MODULE_STATE指針中的部分內容。下面我們再來看看CWinApp中的_AFX_CMDTARGET_GETSTATE()又是什么:
#ifdef _AFXDLL
#define _AFX_CMDTARGET_GETSTATE() (m_pModuleState)
#else
#define _AFX_CMDTARGET_GETSTATE() (AfxGetModuleState())
#endif
如果此處不考慮_AFXDLL情況,那么在CWinApp中將直接調用 AfxGetModuleState()函數,瞧,又是AfxGetModuleState()函數。于是我們可以這么考慮,在內存中有一份全局或靜態的 AFX_MODULE_STATE類,AfxGetModuleState只是返回這一份全局指針(猜測)。在CWinApp中通過對AFX_MODULE_STATE中的m_pCurrentWinApp填充this指針后,將使全局的AFX_MODULE_STATE保存當前WinApp中的CWinApp指針。
其中的特殊指之處在于使用了this指針,當基類被繼承后,this指針將代表繼承類的this指針。因此任何一個CWinApp被繼承后,如繼承類為CMyWinApp,那么 CMyWinApp的地址將被存在AFX_MODULE_STATE的全局變量之中,當使用AfxGetModuleState()函數獲取 AFX_MODULE_STATE時便可獲取當前系統的CMyWinApp指針m_pCurrentWinApp。
下面總結一下:
當前指針通過AfxGetApp()通過返回afxCurrentWinApp,而afxCurrentWinApp宏為AfxGetModule()- >m_pCurrentWinApp,即AfxGetApp()通過返回AfxGetModule()->m_pCurrentWinApp 獲取當前App的指針,而AfxGetModule()->m_pCurrentWinApp指針通過CWinAPP構造函數通過this指針設 置,而this指針恰恰就是當前App的指針(this將轉換為繼承類的指針)。
因此也就解釋了不管當前App被怎么繼承,AfxGetModule()->m_pCurrentWinApp始終能夠獲取當前App的指針的原因了。
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成