《深入淺出MFC》學習筆記之二 (轉)
MFC的來龍去脈
-《深入淺出MFC》學習筆記之二
作者:XGM 2001-8-14
MFC程式也是程式,所以它也有一個WinMain,但是我們在程式中看不到它的蹤影。實際上,在程式進入點之前,有一個(而且只有一個)全域性(在Hello程式中名為theApp),這是所謂的application
,當操作將程式載入並啟用時,這個全域性物件獲得,其構造會先,比WinMain更早。
書中所舉Hello程式,是一個簡單的MFC程式,其主體在於WinMain和WndProc,而這兩個部分其實都有相當程度的不變性。MFC就是把有著相當固定行為的WinMain內部操作封裝在CWinApp中;把有著相當固定行為的WndProc內部操作封裝在CFrameWnd中。也就是說,CWinApp代表程式本體,CFrameWnd代表一個主框視窗
雖然WinMain和WndProc內部操作有相當程度的不變性,但面對不同應用程式也需有變化,所以必須以這兩個類為基礎,派生自己的類,並改寫其中一部分成員函式。
CWinApp----取代WinMain的地位
傳統上SDK程式的WinMain所完成的工作現由CWinApp的三個函式完成:
virtual BOOL InitApplication( );
virtual BOOL InitInstance( );
virtual BOOL Run( );
CFrameWnd-----取代WndProc的地位
CFrameWnd主要用來掌握一個視窗
引爆器------Application object
當執行Hello程式時,這個全域性物件產生,於是建構函式(見APPCORE.CPP)執行起來,CWinApp之中的成員變數將因為這個全域性物件的誕生而獲得配置與初值,配置完成後,WinMain(MFC早已準備好,並由連結器直接加到應用程式中去的)登場。
AfxWinInit:是繼CWinApp建構函式之後的第一個操作;
此後的操作是pApp->InitApplication(其中的pApp指向CMyWinApp物件,即本例中的theApp),因為CMyWinApp繼承自CWinApp,而InitApplication又是CWinApp的一個虛擬函式,我們沒有改寫它(大部分情況下也不需要改它),所以上述操作相當於CWinApp::InitApplication。此程式的程式碼出現在APPCORE.CPP中;
繼InitApplication之後,AfxWinMain呼叫pApp->InitInstance,InitInstance是CWinApp的一個虛擬函式(應用程式一定要改寫這個函式,因為它在CWinApp中是個空函式,沒有任何默任操作),我們改寫了它,所以上述操作就是調有我們自己的這個InitInstance函式,我們將在該處展開我們的主視窗生命。
CMyWinApp::InitInstance一開始new了一個CMyFrameWnd物件,new會引發建構函式CmyFrameWnd::CMyFrameWnd,其中呼叫了CFrameWnd的成員函式Create,它將產生一個視窗。
Create函式共八個引數,第一個,指定WNDCLASS視窗類,如果放置NULL,表示要以MFC內建的視窗類產生一個標準的外框視窗(Create函式在產生視窗之前會引發視窗類的註冊操作,下一段講述這一內容);第二個,指定視窗標題;第三個,指定視窗風格,預設是WS-OVERLAPPEDWINDOW,如果你不想要視窗右上角的極大極小鈕,可以改成WS-OVERLAPPED|WS-CAPTION|WS-SYSMENU|WS-THICKFRAME|WS-MINIMIZEBOX|WS-MAXIMIZEBOX,如果希望有垂直捲軸,再加上WS-VSCROLL;第四個引數,指定視窗的位置與大小,預設值rectDefault
;第五個,指定父視窗,第六個指定選單;第七個,為擴充風格,唯有以:CreateWindowEx(而非:CreateWindow)函式才能完成,事實上,CFrameWnd:Create最終呼叫的正是:CreateWindowEx;第八個,是一個指向CCreateContext結構的指標,利用它,在具備Document/View結構的程式中初始化外框視窗,預設值NULL
CFrameWnd:Create在函式中呼叫CreateEx(CWnd有這個成員函式,但其派生類CFrameWnd並沒有,所以這裡呼叫的實際上是CWnd:CreateEx);後者又呼叫PreCreateWindow虛擬函式(它在CWnd及其派生類CFrameWnd都有定義,所以實際上呼叫的是CFrameWnd::PreCreateWindow),這個函式呼叫了AfxDeferRegisterClass宏,它表示如果變數afxRegisteredClass的值顯示系統已經註冊了fClass
這種視窗類,MFC啥也不做,否則就呼叫AfxEndDeferRegisterClass(fClass){它呼叫兩個函式完成實際的視窗類註冊操作,一個是RegisterWithIcon,一個是AfxRegisterClass},準備註冊之。
視窗顯示與
CMyFrameWnd::CMyFrameWnd結束後,視窗已經誕生出來;程式又回到CMyWinApp::InitInstance,於是呼叫ShowWindow函式令視窗顯示出來,並呼叫UpdateWindow函式令Hello程式送出WM-PAINT
CWinApp::Run----程式生命的活水源頭
Run又是CWinApp的一個虛擬函式,我們沒有改寫它(大部分情況下也不需要改它),所以上述操作相當於呼叫CWinApp::Run
WinMain已由MFC提供,視窗類已由MFC註冊完成,連視窗函式也都由MFC提供
把訊息與處理函式連線在一起:Message Map機制
MFC提供給應用程式使用的“很方便的介面”是兩組宏,以Hello為例,第一個操作是在Hello.h的CMyFrameWnd加上DECLARE-MESSAGE-MAP;第二個操作是在Hello.cpp的任何位置(當然不能在函式內)使用宏
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_COMMAND(IDM_ABOUT, OnAbout)
ON_WM_PAINT()
END_MESSAGE_MAP()
來龍去脈總整理
程式的誕生
Application object 產生, 於是獲得配置,初值亦設立了。
AfxWinMain執行AfxWinInit,後者又調有AfxInitThread,把訊息佇列儘量加
大到96
AfxWinMain執行InitApplication。這是CWinApp的虛擬函式,我們通常不改寫它
AfxWinMain執行InitInstance。這是CWinApp的虛擬函式,我們必須改寫它
CMyWinApp::InitInstance “new”了一個CMyFrameWnd物件
CmyFrameWnd建構函式呼叫Create,產生主視窗。我們在Create引數中指定的視窗類是NULL,於是MFC根據視窗種類,自行為我們註冊一個名為“AfxFrameOrView42d”的視窗類。
回到InitInstance中繼續執行ShowWindow,顯示視窗
執行UpdateWindow,於是發出WM-PAINT
回到AfxWinMain,執行Run,進入訊息迴圈。
程式開始執行:
程式獲得WM-PAINT訊息(由CWinApp::Run中的::GetMessage迴圈)
WM-PAINT經由::DispatchMessage送到視窗函式CWnd::DefWindowProc中。
CWnd::DefWindowProc將訊息傳遞到訊息對映表格
傳遞過程中發現有相符專案,於是呼叫專案中對應的函式。此函式是利用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間的宏設立起來的。
標準訊息的處理程式亦有標準命名,例如WM-PAINT必由OnPaint處理
程式的死亡:
使用者單擊File/Close,於是發出WM-CLOSE
CMyFrameWnd並沒有設定WM-CLOSE處理程式,於是交給預設的處理程式
預設函式對於WM-CLOSE的處理方式是呼叫::DestroyWindow,並因而發出WM-DESTROY
預設的WM-DESTROY處理方式是呼叫::PostQuitMessage,因此發出WM-QUIT
CWinApp::Run收到WM-QUIT後會結束內部之訊息迴圈,然後呼叫ExitInstance,這是CWinApp的一個虛擬函式;如果CMyWinApp改寫了ExitInstance,那麼CWinApp::Run所呼叫的就是CMyWinApp::ExitInstance,否則就是CWinApp::ExitInstance
最後回到AfxWinMain,執行AfxWinTerm,結束程式
附Hello程式部分程式碼:
Hello.cpp
#include "Stdafx.h"
#include "Hello.h"
#include "Re.h"
CMyWinApp theApp; // application object
//--------------------------------------------------------------------
// CMyWinApp's member
//--------------------------------------------------------------------
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
//--------------------------------------------------------------------
// CMyWinApp's member
//--------------------------------------------------------------------
BOOL CMyWinApp::OnIdle(LONG lCount)
{
CMyFrameWnd* pWnd = (CMyFrameWnd*)m_pMainWnd;
pWnd->IdleTimeHandler(lCount);
return TRUE;
}
//--------------------------------------------------------------------
// CMyFrameWnd's member
//--------------------------------------------------------------------
CMyFrameWnd::CMyFrameWnd()
{
Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault,
NULL, "MainMenu"); }
//--------------------------------------------------------------------
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_COMMAND(IDM_ABOUT, OnAbout)
ON_WM_PAINT()
END_MESSAGE_MAP()
//--------------------------------------------------------------------
void CMyFrameWnd::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
dc.SetTextAlign(TA_BOTTOM | TA_CENTER);
::LineDDA(rect.right/2, 0, rect.right/2, rect.bottom/2,
(LINEDDAPROC) LineDDACallback, (LPARAM) (LPVOID) &dc);
}
//--------------------------------------------------------------------
VOID CALLBACK CMyFrameWnd::LineDDACallback(int x, int y, LPARAM
lpdc)
{
static char szText[] = "Hello, MFC";
((CDC*)lpdc)->TextOut(x, y, szText, sizeof(szText)-1);
for(int i=1; i<50000; i++);
}
//--------------------------------------------------------------------
void CMyFrameWnd::OnAbout()
{
CDialog about("AboutBox", this); // "AboutBox"
about.odal();
}
//--------------------------------------------------------------------
void CMyFrameWnd::IdleTimeHandler(LONG lCount)
{
CString str;
CRect rect(10,10,200,30);
CDC* pDC = new CClientDC(this);
str.Format("%010d", lCount);
pDC->DrawText(str, &rect, DT_LEFT | DT_TOP);
}
Hello.h
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance(); //
virtual BOOL OnIdle(LONG lCount); // OnIdle e?
};
//--------------------------------------------------------------------
class CMyFrameWnd : public CFrameWnd
{
public:
CMyFrameWnd(); // constructor
afx_msg void OnPaint(); // for WM_PAINT
afx_msg void OnAbout(); // for WM_COMMAND (IDM_ABOUT)
void IdleTimeHandler(LONG lCount); // we want it call by
CMyWinApp::OnIdle
private:
DECLARE_MESSAGE_MAP() // Declare Message Map
static VOID CALLBACK LineDDACallback(int,int,LPARAM);
//?
};
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990808/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 深入淺出DPDK學習筆記——前言筆記
- 深度學習深入淺出深度學習
- 深入淺出redux學習Redux
- 深入淺出node讀書筆記筆記
- 機器學習深入淺出機器學習
- OpenFeign深入學習筆記筆記
- 前端筆記之React(五)Redux深入淺出前端筆記ReactRedux
- elasticsearch 學習筆記之二 常見介面Elasticsearch筆記
- 深入淺出學習決策樹(二)
- 深入淺出學習決策樹(一)
- 好程式設計師web前端培訓學習筆記Vue學習筆記之二程式設計師Web前端筆記Vue
- MFC學習(五)
- 深入淺出eslint——關於我學習eslint的心得EsLint
- 深入淺出FE(十四)深入淺出websocketWeb
- repuest轉發學習筆記一筆記
- 【學習筆記】CSS深入理解之margin筆記CSS
- 【學習筆記】CSS深入理解之overflow筆記CSS
- 【學習筆記】CSS深入理解之relative筆記CSS
- 深入淺出學Java-HashMapJavaHashMap
- 深入淺出Java記憶體模型Java記憶體模型
- 深入淺出記憶體馬(一)記憶體
- 《深入淺出node.js》第四章——記憶體控制(筆記)Node.js記憶體筆記
- 《深入淺出深度學習》之“從邏輯學到認知科學”深度學習
- Python——格式轉換的學習筆記Python筆記
- 10g NewFeatures學習筆記(轉)筆記
- 深入淺出 MFC_華中理 工_簡體版電子書pdf下載
- 深入淺出說強制型別轉換型別
- Linux:深入淺出 Linux 共享記憶體Linux記憶體
- 深入淺出Netty記憶體管理 PoolChunkNetty記憶體
- 深入淺出webpack學習(14)–為單頁應用生成HTMLWebHTML
- 淺讀-《深入淺出Nodejs》NodeJS
- golang學習筆記(二)—— 深入golang中的協程Golang筆記
- 【學習筆記】CSS深入理解之vertical-align筆記CSS
- numpy的學習筆記\pandas學習筆記筆記
- 彙編學習筆記之轉移指令筆記
- 依賴倒轉原則--學習筆記筆記
- 《深入淺出神經網路與深度學習》譯者後記神經網路深度學習
- 【演算法學習筆記】淺談懸線法演算法筆記
- 機器學習框架ML.NET學習筆記【2】入門之二元分類機器學習框架筆記