MFC和Win32的區別
MFC把具有相當固定行為的WinMain內部操作封裝在CWinApp中,把有著相當固定行為的WndProc內部操作封裝在CFrameWnd中。
幾乎可以說CWinApp用來取代WinMain在SDK程式中的地位,CFrameWnd取代SDK程式中視窗函數的地位。
首先MFC程式需要下面函數庫:
(1) Windows C Runtime函數庫:LIBC.LIB / MSVCRT.LIB / MSVCRTD.LIB
(2) DLL Import函數庫:GDI32.LIB / USER32.LIB / KERNEL32.LIB
(3) MFC函數庫(AFX函數庫):MFC42.LIB / MFC42D.LIB……
同時,MFC程式需要下面標頭檔:
(1) Stdafx.h:先行編譯標頭檔,其內只是載入其他的MFC標頭檔。
(2) Afxwin.h:每個MFC程式都必須載入它,因為它以及它所載入的檔案聲明了所有的MFC類,此檔案含有Afx.h,後者又載入Afxvver_.h,後者又載入Afxv_w32.h,後者又載入windows.h(SDK程式必須要的標頭檔)。
(3) Afxext.h:使用工具列、狀態列的程式必須載入這個檔案。
(4) Afxdlgs.h:使用通用型對話方塊的MFC程式需要此檔案,其內部載入COMMDLG.H
(5) Afxcmn.h:使用Win9x新增的通用型控制項的MFC程式必須載入此檔案。
(6) Afxcoll.h:使用Collections Classes的程式要此檔案
(7) Afxres.h:MFC程式的RC檔案必須載入此檔案。
[解釋]先行編譯標頭檔:所謂先行編譯標頭檔是指將 .H 檔案第一次編譯後的結果儲存起來,第2次編譯的時候就可以直接從磁碟上取出來用。
一個具體而微的MFC程式和Win32之間的關係:
MFC程式也是Windows程式,所以它應該有一個WinMain,但在程式進入點之前,還有一個全域對象theApp,這是所謂的應用程式物件。當作業系統將程式載入並啟用的時候,這個全域對象獲得配置,其建構函式會先執行,必WinMain更早。
CmyWinApp theApp;
theApp是程式的應用程式物件,每一個MFC程式有且只有這麼一個,當執行程式時,這個全域對象產生,於是建構函式執行起來。一般來說CwinApp的建構函式被執行。CwinApp之中的成員變數將因為theApp這個全域對象的誕生而獲得配置與初值。
theApp配置完成後,WinMain登場,我們並沒有撰寫WinMain程式碼,這是MFC早已準備好並由連接器直接加到應用程式代碼中的。加入如下代碼:
extern “C” int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
其中AfxWinMain定義如下:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
int nReturnCode = -1;
CwinApp *pApp = AfxGetApp();
AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
pApp->InitApplication();
pApp->InitInstance();
nReturnCode = pApp->Run();
AfxWinTerm();
Return nReturnCode;
}
關於AfxWinMain的四個主要操作說明:
(1) AfxWinInit——AFX內部初始化操作。它是繼CwinApp建構函式之後的第一個操作。在這函數內對theApp的某些成員初始化,而且還調用了AfxInitThread函數,把訊息佇列盡量加大到96。
(2) CwinApp::InitApplication。InitApplication是CwinApp的一個虛函數,一般情況下不需要改寫它。在此函數中的操作都是MFC為了內部管理而作的(DocManager相關)。
(3) CmyWinApp::InitInstance。每個MFC程式都應該改寫CwinApp::InitInstance這個函數,因為它在CwinApp中只是一個空函數。在這個函數裡面,代碼如下:
BOOL CmyWinApp::InitInstance()
{
m_pMainWnd = new CmyFrameWnd();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
其中一開始就new了一個CmyFrameWnd對象,準備用作主框視窗的C++對象,引發了CmyFrameWnd的建構函式:
CmyFrameWnd::CmyFrameWnd
{
Create(NULL,”hello MFC”, WS_OVERLAPPEDWINDOW, rectDefault, NULL,”MainMenu”);
}
Create是CframeWnd的成員函數,CmyFrameWnd中並沒有改寫它。由於Create的第一個參數指定WNDCLASS視窗類別名字,現在為NULL表示以MFC內建的視窗類別產生一個標準的外框視窗。
在CframeWnd::Create(…)函數中,調用了CreateEx函數,由於CframeWnd中並沒有改寫CreateEx函數,所以實際上調用的是CWnd::CreateEx。在CreateEx這個函數中,調用了PreCreateWindow和CreateWindowEx這兩個函數。由於CframeWnd中改寫了PreCreateWindow,所以這裡調用的是CframeWnd::PreCreateWindow。在PreCreateWindow裡面,調用了AfxDeferRegisterClass宏,該宏的定義如下:
#define AfxDeferRegisterClass(fClass) \ ((afxRegisteredClasses & fClass) TRUE : AfxEndDeferRegisterClass(fclass))
如果變數afxRegisteredClasses的值顯示系統已經註冊了fclass這種視窗類別,MFC就啥也不做,否則就調用AfxEndDeferRegisterClass(fclass),準備註冊之。AfxEndDeferRegisterClass函數中終於聲明了WNDCLASS對象,並且調用了相應的MFC視窗類別,並通過AfxRegisterClass(WNDCLASS*)和RegisterWithIcon這兩個函數來註冊視窗類別。MFC內建6種視窗類別。RegisterWithIcon中用到AfxRegisterClass函數,而AfxRegisterClass函數裡面又調用了RegisterClass函數來註冊視窗類別。不同類的PreCreateWindow成員函數都是在視窗產生之前一刻被調用,準備用來註冊視窗類別的,如果我們指定視窗類別為NULL,那麼就是用系統預設類(MFC內建)。
當建立完視窗以後,程式流程又回到CmyWinApp::InitInstance,於是調用ShowWindow函數令視窗顯示出來,並調用UpdateWindow函數令程式送出WM_PAINT訊息。
(4) CwinApp::Run,由於在CmyWinApp中沒有改寫Run(大部分情況下都不用改寫),所以調用的是CwinApp::Run。在該函數中又調用了CwinThread::Run,CwinThread::Run中調用了PumpMesage()函數,而PumpMessage函數中依次調用GetMessage / TranslateMessag / DispatchMessage函數。程式通過調用DispatchMessage函數,把訊息丟給視窗函數。
(5) 程式根據訊息映射表來判斷訊息,從而做出相應的訊息處理。
至此,MFC程式和Win32程式的關係總算弄明白。
轉自:http://hi.baidu.com/ncudlz/item/17e6a0cd2ba2250dac092f29