1,尋找WinMain人口:
在安裝目錄下找到MFC文件夾下的SRC文件夾,SRC下是MFC源代碼。
路徑:MFC|SRC|APPMODUL.CPP:
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
注意:(#define _tWinMain WinMain)
2,對于全局對象或全局變量來說,在程序運行即WINMAIN函數(shù)加載的時候,已經(jīng)為全局對象或全局變量分配了內(nèi)存和賦初值。
所以:CTEApp theApp;->CTEApp ::CTEApp(){}->_tWinMain(){}
說明:每一個MFC程序,有且只有一個從WinApp類派生的類(應(yīng)用程序類),也只有一個從應(yīng)用程序類所事例化的對象,表示應(yīng)用程序本身。在WIN32程序當中,表示應(yīng)用程序是通過WINMAIN入口函數(shù)來表示的(通過一個應(yīng)用程序的一個事例號這一個標識來表示的)。在基于MFC應(yīng)用程序中,是通過產(chǎn)生一個應(yīng)用程序?qū)ο?,用它來唯一的表示了?yīng)用程序。
3,通過構(gòu)造應(yīng)用程序?qū)ο筮^程中調(diào)用基類CWinApp的構(gòu)造函數(shù),在CWinApp的構(gòu)造函數(shù)中對程序包括運行時一些初始化工作完成了。
CWinApp構(gòu)造函數(shù):MFC|SRC|APPCORE.CPP
CWinApp::CWinApp(LPCTSTR lpszAppName){...}//帶參數(shù),而CTEApp構(gòu)造函數(shù)沒有顯式向父類傳參,難道CWinApp()有默認參數(shù)?見下:
(在CWinApp類定義中, CWinApp(LPCTSTR lpszAppName = NULL); )
注意:CWinApp()函數(shù)中:
pThreadState->m_pCurrentWinThread = this;
pModuleState->m_pCurrentWinApp = this
(this指向的是派生類CTEApp對象,即theApp)
調(diào)試:CWinApp::CWinApp();->CTEApp theApp;(->CTEApp ::CTEApp())->CWinApp::CWinApp()->CTEApp ::CTEApp()->_tWinMain(){}
4,_tWinMain函數(shù)中通過調(diào)用AfxWinMain()函數(shù)來完成它要完成的功能。(Afx*前綴代表這是應(yīng)用程序框架函數(shù),是一些全局函數(shù),應(yīng)用程序框架是一套輔助生成應(yīng)用程序的框架模型,把一些類做一些有機的集成,我們可根據(jù)這些類函數(shù)來設(shè)計自己的應(yīng)用程序)。
AfxWinMain()函數(shù)路徑:MFC|SRC|WINMAIN.CPP:
在AfxWinMain()函數(shù)中:
CWinApp* pApp = AfxGetApp();
說明:pApp存儲的是指向WinApp派生類對象(theApp)的指針。
//_AFXWIN_INLINE CWinApp* AFXAPI AfxGetApp()
// { return afxCurrentWinApp; }
調(diào)用pThread->InitInstance()
說明:pThread也指向theApp,由于基類中virtual BOOL InitApplication()定義為虛函數(shù),所以調(diào)用pThread->InitInstance()時候,調(diào)用的是派生類CTEApp的InitInstance()函數(shù)。
nReturnCode = pThread->Run();
說明:pThread->Run()完成了消息循環(huán)。
5,注冊窗口類:AfxEndDeferRegisterClass();
AfxEndDeferRegisterClass()函數(shù)所在文件:MFC|SRC|APPCORE.CPP
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){...}
說明:設(shè)計窗口類:在MFC中事先設(shè)計好了幾種缺省的窗口類,根據(jù)不同的應(yīng)用程序的選擇,調(diào)用AfxEndDeferRegisterClass()函數(shù)注冊所選擇的窗口類。
調(diào)試:CWinApp::CWinApp();->CTEApp theApp;(->CTEApp ::CTEApp())->CWinApp::CWinApp()->CTEApp ::CTEApp()->_tWinMain(){}//進入程序
->AfxWinMain();->pApp->InitApplication();->pThread->InitInstance()//父類InitInstance虛函數(shù);->CTEApp::InitInstance()//子類實現(xiàn)函數(shù);->AfxEndDeferRegisterClass(LONG fToRegister)//注冊所選擇的窗口類(出于文檔管理,注冊提前,正常的應(yīng)在PreCreateWindow中進行注冊)//之后進入創(chuàng)建窗口階段(以下再不做調(diào)試)
6,PreCreateWindow()://主要是注冊窗口類
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
return TRUE;
}
說明:
CFrameWnd::PreCreateWindow()函數(shù)所在文件:MFC|SRC|WINFRM.CPP
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
//判斷AFX_WNDFRAMEORVIEW_REG型號窗口類是否注冊,如果沒有注冊則注冊
cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background
//把注冊后的窗口類名賦給cs.lpszClass
}
if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
cs.style |= FWS_PREFIXTITLE;
if (afxData.bWin4)
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;
}
其中:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);//PreCreateWindow()是個虛函數(shù),如果子類有則調(diào)用子類的。
#define VERIFY(f) ASSERT(f)
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
define AFX_WNDFRAMEORVIEW_REG 0x00008
const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;//WINCORE.CPP文件中,定義為全局數(shù)組。
//#define AFX_WNDFRAMEORVIEW AFX_WNDCLASS("FrameOrView")
7,創(chuàng)建窗口:
Create()函數(shù)路徑:MFC|SRC|WINFRM.CPP:
CFrameWnd::Create(...){
...
CreateEx(...);//從父類繼承來的,調(diào)用CWnd::CreateEx().
...
}
CWnd::CreateEx()函數(shù)路徑:MFC|SRC|WINCORE.CPP
BOOL CWnd::CreateEx(...){
...
if (!PreCreateWindow(cs))//虛函數(shù),如果子類有調(diào)用子類的。
{
PostNcDestroy();
return FALSE;
}
...
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
...
}
說明:CreateWindowEx()函數(shù)與CREATESTRUCT結(jié)構(gòu)體參數(shù)的對應(yīng)關(guān)系,使我們在創(chuàng)建窗口之前通過可PreCreateWindow(cs)修改cs結(jié)構(gòu)體成員來修改所要的窗口外觀。PreCreateWindow(cs))//是虛函數(shù),如果子類有調(diào)用子類的。
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
typedef struct tagCREATESTRUCT { // cs
LPVOID lpCreateParams;
HINSTANCE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCTSTR lpszName;
LPCTSTR lpszClass;
DWORD dwExStyle;
} CREATESTRUCT;
8,顯示和更新窗口:
CTEApp類,TEApp.cpp中
m_pMainWnd->ShowWindow(SW_SHOW);//顯示窗口,m_pMainWnd指向框架窗口
m_pMainWnd->UpdateWindow();//更新窗口
說明:
class CTEApp : public CWinApp{...}
class CWinApp : public CWinThread{...}
class CWinThread : public CCmdTarget
{
...
public:
CWnd* m_pMainWnd;
...
...
}
9,消息循環(huán):
int AFXAPI AfxWinMain()
{ ...
// Perform specific initializations
if (!pThread->InitInstance()){...}
//完成窗口初始化工作,完成窗口的注冊,完成窗口的創(chuàng)建,顯示和更新。
nReturnCode = pThread->Run();
//繼承基類Run()方法,調(diào)用CWinThread::Run()來完成消息循環(huán)
...
}
////////////////////////////////////////////////////////////////
CWinThread::Run()方法路徑:MFC|SRC|THRDCORE.CPP
int CWinThread::Run()
{ ...
// phase2: pump messages while available
do//消息循環(huán)
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())//取消息并處理
return ExitInstance();
...
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
...
}
說明:
BOOL PeekMessage(,,,,)函數(shù)說明
The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure.
If a message is available, the return value is nonzero.
If no messages are available, the return value is zero.
/////////////////////////////////////////////////////////////
BOOL CWinThread::PumpMessage()
{
...
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))//取消息
{...}
...
// process this message
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);//進行消息(如鍵盤消息)轉(zhuǎn)換
::DispatchMessage(&m_msgCur);//分派消息到窗口的回調(diào)函數(shù)處理(實際上分派的消息經(jīng)過消息映射,交由消息響應(yīng)函數(shù)進行處理。)
}
return TRUE;
}
9,文檔與視結(jié)構(gòu):
可以認為View類窗口是CMainFram類窗口的子窗口。
DOCument類是文檔類。
DOC-VIEW結(jié)構(gòu)將數(shù)據(jù)本身與它的顯示分離開。
文檔類:數(shù)據(jù)的存儲,加載
視類:數(shù)據(jù)的顯示,修改
10,文檔類,視類,框架類的有機結(jié)合:
在CTEApp類CTEApp::InitInstance()函數(shù)中通過文檔模板將文檔類,視類,框架類的有機組織一起。
...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTEDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTEView));
AddDocTemplate(pDocTemplate);//增加到模板
...