首先來一張類結構層次圖
然後我們進入討論的正題吧!
CWinApp* pApp = AfxGetApp(),GfxGetApp是取得當前CMyApp的對象的一個函數 這樣我們用當前的App對象(衍生類別)附值給CWinApp指標(父類)。這樣下面pApp.InitInstance()
調用的就是衍生類別的因為它是虛函數,如果衍生類別沒有重寫那就調用基類一層一層往上找
標號為3,4處:
首先InitApplication和InitInstance都是虛函數所以如果子類APP也就是自己的程式對這兩個函數重載那麼實際上啟動並執行是自己的App類定義重寫後的函數,一般情況下我們不重載InitApplication這個函數,但是InitInstance是一個空的虛函數,所以我們的程式一定要重載它!所以這裡我們的pApp->InitInstance()是調用的CMyWinApp->InitInstance()這個函數。
InitInstance()這個函數是初始化視窗的,在本例子裡更是在App類裡面調用初始化的是一個主視窗,在win32程式中它是用CreateWindow(...)建立視窗中,但在mfc中我們用不著這麼做,只要初始化相關視窗類別(基類為CWnd)的執行個體就會調用相互關聯類型的Create()的,圖中初始化的是CMyFrameWnd這個類的對象的,當然我們可以用別的視窗類別比如說對話方塊類。
在win32程式中我們把"註冊視窗類別"的相關操作放在InitApplication這個函數裡面,但是MFC中不是這樣的,讓我們看看這個函數吧:
你看這個函數並沒有註冊視窗類別,那麼我們程式運行完這個函數就運行到 InitInstance中開始初始化相關的類型的視窗了,按道理說createwindow()前一定要先註冊視窗類別的啊?沒有視窗類別名稱怎麼建立視窗呢?還有視窗過程也沒指名啊?這就到了問題的關鍵點了:
程式進入到了InitInstance()中--〉CMyFrameWnd對象的建構函式--〉這個視窗的Create()函數---〉然後不知道是怎麼指定的就到了CMYFrameWnd::CreateEx()-->因為這個類沒有重寫這個函數就到了CWnd::CreateEx() ,其實就是這個建構函式構造我們現在要建立的這個視窗的!讓我們看看真身:
我們看到這裡給視窗類別的結構體cs先附了一些東西但缺少視窗類別名和視窗過程的指向這兩個東西,然後由於這個函數在子類CFrameWnd中被重寫所以進入CFrameWnd::PreCreateWindow(cs)中,玄機就在這個函數了,這個函數將給cs沒有附的視窗類別名和視窗過程的指向附值。這個過程比較繁瑣。我這裡就描述一下吧,深入淺出中很詳細的。
在這個函數中判斷cs這個視窗類別是不是進行註冊過的,如果進行註冊過就什麼都不做,如果沒有註冊就調用一個函數來對cs的視窗類別型和視窗過程附值然後註冊它,簡寫一個這個函數:
BOOL AFXAPI AfxEndDeferRegisterClass(short cs)
{
cs.lpfnWndProc = DefWindowProc;//現在視窗過程用DefWindowProc,一會在AfxHookWindowCreate(this)中進行了改寫
cs.hInstance = AfxGetInstanceHandle();
cs.hCursor = afxData.hcurArrow;
//這雷根據判斷不同類型的視窗註冊了幾種不同視窗類別(比如工具條之類的好像和其它的視窗類別不一樣),我們這裡先不管//,唯寫出WND這個類是怎麼註冊的
cs.style = CS_DBLCIKS|CS_HREDRAW|CS_VREDRAW;
cs.lpzClassName = _afxwnd;//_afxwnd
bResult = AfxRegisterClass(&cs);//要的就是這個AfxRegisterClass,這下子是真的註冊成功了。
}
這下子我們要建立的這個視窗的視窗類別型就註冊成功了,現在可以用這個視窗類別進行建立視窗了!但還要注意在CreateWindowEx之前還有AfxHOOKWindowCreate(this)這個函數之前還有一個叫做AfxHookWindowCreate(this)這個函數,這是一個鉤子函數,作用是利用SetWindowLong設定視窗過程為AfxWndProc,然後AfxWndProc()-->AfxCallWndProc-->WindowProc .沒錯!當捕捉到該視窗類別對象的訊息後首先就跑到WindowProc裡了!
AfxHOOKWindowCreate(this)運行完了!那麼建立一個視窗的"前戲"就都ok了!下面就走到CreateWindowEx建立這個視窗了~!~
注意:本例子講的是程式從進入主函數到它的第一個視窗----主視窗建立的詳細流程,這個主視窗是一個CFrameWnd類的執行個體。我想說的是其它Wnd類的子類的初始化也應該是這樣,比如說我們建立一個對話方塊CMyDialog,也是大概上面所述的那個流程,我們一初始化CMyDialog就會走到CDialog::CreateEx()這個函數然後PreCreateWindow中註冊視窗類別指定類名和視窗過程函數,然後CreateWindowEX..........反正這都封裝好了!我們只要初始化就行了!