《深入淺出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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 《深入淺出MFC》學習筆記之一 (轉)筆記
- 《深入淺出MFC》讀書筆記(一,二) (轉)筆記
- 讀深入淺出MFC的一節筆記 (轉)筆記
- 深入淺出DPDK學習筆記——前言筆記
- 【筆記】《深入淺出MFC》第6章 MFC程式的生死因果筆記C程式
- 簡單而完整:MFC骨幹程式(深入淺出MFC之讀書筆記)筆記
- 【筆記】《深入淺出MFC》第5章 總觀Application Framework筆記APPFramework
- 評侯捷的《深入淺出MFC》和李久進的《MFC深入淺出》
- 深入淺出redux學習Redux
- 深度學習深入淺出深度學習
- 《Mastering Delphi 6學習筆記》之二 (轉)AST筆記
- Oracle學習筆記之二Oracle筆記
- 深入淺出node讀書筆記筆記
- 《深入淺出MySQL》讀書筆記MySql筆記
- MSSQL配置學習筆記之二SQL筆記
- 深入淺出Nodejs讀書筆記NodeJS筆記
- 前端筆記之React(五)Redux深入淺出前端筆記ReactRedux
- 深入淺出學習決策樹(二)
- 深入淺出學習決策樹(一)
- C#學習筆記一:深入HelloWorld內部 (轉)C#筆記
- 好程式設計師web前端培訓學習筆記Vue學習筆記之二程式設計師Web前端筆記Vue
- 深入淺出OOD(一) (轉)
- sed學習筆記(轉)筆記
- gurb學習筆記(轉)筆記
- ANT學習筆記 (轉)筆記
- GRUB學習筆記(轉)筆記
- TreeView學習筆記 (轉)View筆記
- 深入淺出undo記載01
- 深入淺出undo記載02
- 深入淺出undo記載03
- ActiveX深入淺出(一) (轉)
- ActiveX深入淺出(二) (轉)
- 深入淺出HOOKS(之伍) (轉)Hook
- 深入淺出HOOKS(之陸) (轉)Hook
- 深入淺出談防火牆(轉)防火牆
- Object C學習筆記8-字串NSString之二Object筆記字串
- MSSQL2005-QUERY EXECUTION學習筆記之二SQL筆記
- ctf學習筆記[轉載]筆記