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的指針的原因了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM