習慣的思維用習慣了C的人要看一個程序時首先會想到找到那個main函數(shù)在哪,然后再順著往下看.因為main函數(shù)作為程序的入口點,整個程序都是從那開始執(zhí)行的.當在C++中SDK(win32 API project)開發(fā)時也繼承沿用C的思維,是有個main函數(shù),不過現(xiàn)在的main函數(shù)改名字了,叫WinMain,當然有時還有變體,比如叫_tWinMain,反正名字中總會帶個Main,讓我們一看就知道.而在QT中就跟C一樣,就老實的來個標準的main函數(shù). 我們會發(fā)現(xiàn)C++中可以有一個單獨的main函數(shù),不用包含在哪個類中,另外還有不屬于任何類的全局變量或全局函數(shù)這自然就不是純粹的面向?qū)ο笳Z言了.所以說C++支持多種編程范式嘛,可以是跟C完全一樣的面向過程范式,或者再加些普通的類就是基于對象的范式了,如果再用到繼承和多態(tài)就是面向?qū)ο罅?而要是用到模板就是泛型范式了.而且這些范式可以互相混合用.而C#就是純的面向?qū)ο?所以它里面雖然也有main函數(shù),但也是要放在一個類里面去,至于具體放哪個類無所謂,你隨便放.一般默認是放Program這個類里.當然并不是說純的面向?qū)ο缶捅然旌系姆妒胶?應(yīng)該各有優(yōu)缺點. 哎扯得有點遠了,言歸正傳.
SDK中的流程開發(fā)一個帶界面的SDK程序大致流程是這樣的.首先自然是要有個main函數(shù)做入口點.然后按下面的步驟來(為了討論方便,只說大概流程,代碼也是不完整的) int _tWinain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; InitApplicatio(HINSTANCE hInstance) //第1步,注冊窗體類,并在這里指定了窗體過程WndProc InitInstance(HINSTANCE hInstance, int nCmdShow) //第2步,創(chuàng)建窗體 while (GetMessage(&msg, NULL, 0, 0)) //第3步消息循環(huán),分派消息 { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; //第4步,退出程序 } BOOL InitApplicatio(HINSTANCE hInstance) { return RegisterClass(...); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { CreateWindow(...); //創(chuàng)建窗體 ShowWindow(...); //顯示窗體 UpdateWindow(...); //送出WM_PAINT return TRUE; } LRESULT CALLBACK WndProc(...){ }
在MFC中生成一個有界面的程序大體過程也一樣,只不過封裝起來了.那我們感興趣的就是兩個問題. 1.MFC中有沒有main函數(shù)了,如果有它跑哪去了? 2.如果有main函數(shù),它里面的那4步涉及到的具體操作是否也跟win32 API一樣? 下面我們就來一一解答下
MFC封裝背后流程
實際上候捷那本深入淺出MFC里面有講的很清楚了.不過由于講的太詳細了,有幾十頁,看的容易暈,而且他舉的例都是老版本的MFC類,在新版本中一些類的函數(shù)會有一點點變化. 我這里就只概括的講下最簡潔的流程.先假如有類CMyApp繼承自CWinApp吧
1.針對第一個問題,MFC里是有用到main函數(shù)的// export WinMain to force linkage to this module extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, int nCmdShow); 就是這一個函數(shù),在MFC的源文件appmodul.cpp中能看到這些代碼,那這個main怎么被MFC調(diào)用的呢,你看那注釋,是linkage to this module,也就是被鏈接器去調(diào)用的.準確說是被C-Runtime DLL,C運行時動態(tài)鏈接庫調(diào)用的. 調(diào)用main的順序 我們知道在MFC中能從代碼里看到的入口點是定義一個全局的繼承于CWinApp的類.比如CMyApp theApp;這樣定義下.在C++中全局變量是先于main被執(zhí)行的,所以先初始化theApp后才接著調(diào)用main
2.針對第2個問題,main函數(shù)里具體的操作.知道了有main函數(shù),你心里可能有一絲安慰了.但還是有些覺得不安的是這main函數(shù)里的具體操作是否跟SDK中的一樣,是不是也來那么幾步,先注冊窗口再創(chuàng)建窗口之類的. 答案是MFC調(diào)用的main函數(shù)大概流程差不多是那樣,但實現(xiàn)細節(jié)很不一樣.我們看下上面說的AfxWinMain里面的內(nèi)容是啥吧.你可以在winmain.cpp中看到詳細代碼. 把這個main函數(shù)簡化一下,做的操作大概是這樣, AfxWinMain(...) { //先通過一個全局函數(shù)獲得CWinApp和CWinThread的指針,因為調(diào)用main之前已經(jīng)初始化了這兩個類.CMyApp初始化時也會初始化他的父類CWinApp,及父類的父類CWinThread CWinThread* pThread = AfxGetThread(); CWinApp* pApp = AfxGetApp();
//這下面幾個函數(shù)就差不多是完成前面講的SDK中的所有步驟 pApp->InitApplication(); pThread->InitInstance(); pThread->Run();
AfxWinTerm(); //結(jié)束程序 } 反正結(jié)束程序我們就不用管了,重點關(guān)心前面的三步,注冊窗口,創(chuàng)建窗口,還有消息分派. 前面的SDK程序中也恰好有函數(shù)InitApplication 注冊窗口, InitInstance創(chuàng)建并顯示窗口.而Run函數(shù)你猜想可能是分派消息的..其實大體思路還是沒錯,但實現(xiàn)細節(jié)還是有蠻多區(qū)別. pApp->InitApplication();這函數(shù)實際上并沒有注冊窗口.注冊窗口,創(chuàng)建顯示窗口全是在pThread->InitInstance();這函數(shù)中完成,InitInstance是個虛函數(shù),而且我們在自己的代碼中會重寫它.所以最后調(diào)用的是我們自己寫的那個InitInstance函數(shù),這就是面向?qū)ο罄锒鄳B(tài)的功能了啊.你指針最終指向?qū)?yīng)的子類定義的函數(shù). BOOL CMyApp::InitInstance() { m_pMainWnd = new CMyFrameWnd; //這張操作會注冊并創(chuàng)建窗口,m_pMainWnd就是返回的窗口句柄 m_pMainWnd->ShowWindow(m_nCmdShow); //顯示窗口 m_pMainWnd->UpdateWindow(); }
pThread->Run();是分派消息,你可以在thrdcore.cpp中查看CWinThreed的run函數(shù)的源碼,下面摘了一點點. // acquire and dispatch messages until a WM_QUIT message is received. for (;;) {} 不過關(guān)于消息的處理MFC用到了消息映射機制,比如復(fù)雜.這里不討論了,反正大概就把CMyFrameWnd當成是窗口過程就行了.
MFC怎么封裝CreateWindow見: http://blog.csdn.net/weiwenhp/article/details/8796337 總結(jié)起來可以這樣簡單的說,MFC中有main函數(shù),但是由系統(tǒng)去調(diào)用.然后main函數(shù)里面執(zhí)行的操作差不多,只不過它是通過CWinApp和CWinThread的指針去調(diào)用一些相關(guān)的函數(shù).而指針嘛由于調(diào)用了虛函數(shù),所以用到了面向?qū)ο笾械亩鄳B(tài),于是轉(zhuǎn)來轉(zhuǎn)去的.然后最難的地方可能就是消息機制在這里更復(fù)雜一點了.不能簡單的與SDK中做一對一的對比.
|
|
|
來自: ThinkTank_引擎 > 《MFC》