05 MFC框架執行大概流程
阿新 • • 發佈:2019-01-01
先明確以下關係:
CWinApp取代了原來Win32下的WinMain
CFrameWnd取代了原來Win32下的WndProc
除錯程式碼如下:
/* *HelloMFC.h */ #ifndef _HELLO_MFC_ #define _HELLO_MFC_ class CMyApp : public CWinApp{ public: virtual BOOL InitInstance(); }; class CMainWindow : public CFrameWnd{ public: CMainWindow(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() }; #endif
/* *HelloMFC.cpp */ #include <afxwin.h> #include "HelloMFC.h" CMyApp myApp; BOOL CMyApp::InitInstance() { //這裡雖然在堆區建立的物件,但我們並沒有釋放,是因為有一個PostNcDestroy函式在 //視窗銷燬時會被呼叫來銷燬這個物件 m_pMainWnd = new CMainWindow; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd) ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() CMainWindow::CMainWindow() { Create(NULL, TEXT("Hello MFC")); } void CMainWindow::OnLButtonDown(UINT nFlags, CPoint point) { AfxMessageBox(TEXT("OnLButtonDown")); }
我們現在如圖所示F9下斷點,然後F10進入到AfxWinMain中;
下面我們將AfxWinMain提出來寫點註釋:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, int nCmdShow) { ASSERT(hPrevInstance == NULL);//斷言,作用同容錯判斷 //在進入這裡前已經初始化好了myApp int nReturnCode = -1; //以下兩句,效果差不多,取應用程式例項指標 CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp(); /* 下面這個函式我們跟進去,發現其作用是初始化類成員變數,所以我們在我們InitInstance 函式中用的m_nCmdShow成員變數實際在這裡面已經初始化好了,關鍵程式碼如下: CWinApp* pApp = AfxGetApp(); if (pApp != NULL) { // Windows specific initialization (not done if no CWinApp) pApp->m_hInstance = hInstance; hPrevInstance; // Obsolete. pApp->m_lpCmdLine = lpCmdLine; pApp->m_nCmdShow = nCmdShow; pApp->SetCurrentHandles(); } */ if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) goto InitFailure; // 全域性初始化,幾乎不用,我們不去關注它 if (pApp != NULL && !pApp->InitApplication()) goto InitFailure; // 這就是我們的核心,就是我們程式碼中我們的類重寫的虛擬函式,這裡就進到我 //們的InitInstance,這裡也就解釋了為什麼我們的InitInstance()要放回TRUE //如果返回FALSE就會銷燬視窗,退出程式 if (!pThread->InitInstance()) { if (pThread->m_pMainWnd != NULL) { TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n"); pThread->m_pMainWnd->DestroyWindow(); } nReturnCode = pThread->ExitInstance(); goto InitFailure; } //這裡就實現Win32中訊息迴圈,下面把關鍵程式碼貼出來 /* // acquire and dispatch messages until a WM_QUIT message is received. for (;;) { // 根據空閒狀態標誌判斷執行緒是否為空閒,如果是就呼叫OnIdle虛擬函式,我們可以重寫 //這個虛擬函式實現我們想要的效果 while (bIdle && !::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE)) { if (!OnIdle(lIdleCount++)) bIdle = FALSE; // assume "no idle" state } // 非空閒狀態 do { // PumpMessage中有我們熟悉的GetMessage ThranslateMessage //DispatchMessage if (!PumpMessage()) return ExitInstance(); if (IsIdleMessage(&(pState->m_msgCur))) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE)); } */ nReturnCode = pThread->Run(); InitFailure: #ifdef _DEBUG // Check for missing AfxLockTempMap calls if (AfxGetModuleThreadState()->m_nTempMapLock != 0) { TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock); } AfxLockTempMaps(); AfxUnlockTempMaps(-1); #endif AfxWinTerm(); return nReturnCode; }