任何程序都有一個入口函數,我們在學習C語言的時候入口函數是main函數,學習Win32也是有main函數的,Win32的入口函數是_tWinMain(),因為MFC對Win32API進行了封裝,所以在MFC的代碼中我們是找不到_tWinMain()入口函數的,這增加了我們學習MFC的難度,很多同學都不知道程序是從哪里開始運行的,為了解決這個問題,我通過設置斷點的方式,一步一步跟蹤代碼的執行,分析出了MFC整體的運行流程。
首先我使用VisualStudio2010提供的搜索功能搜索_tWinMain(),注意這里搜索的路徑不能是當前工程路徑,當前工程路徑里的文件是找不到的,必須是在安裝目錄里的VC庫里去搜索,如圖11示: 不管MFC怎么進行封裝,它的原理還是和Win32一樣的,所以在庫里里面搜索一定可以找到我們需要的_tWinMain函數,圖13示 可以看到,搜索結果中第一個就是我們要找的函數。進入這個函數之后,設置一個斷點,然后調試整個程序,可以看到程序果然運行到斷點處,圖14示 從_tWinMain函數內部我們發現,里面只有一句代碼:returnAfxWinMain(hInstance,hPrevInstance, lpCmdLine, nCmdShow);也就是說MFC使用AfxWinMain替代了_tWinMain函數,原來的_tWinMain函數實際上是沒有任何用處的,我們繼續跟蹤,圖15示 在AfxWinMain內部我們終于看見我們熟悉的InitInstance()函數了,其中里面的類都是通過繼承和多態的特性進行工作的,CWinApp繼承CWinThread類,我們新建的類CDemoADOApp繼承CWinApp,任何應用程序只有一個CWinApp類,在CWinThread的成員函數中有InitInstance、Run、ExitInstance三個主要的函數,且這三個函數都是虛函數,我們的類CDemoADOApp通過繼承CWinApp類,重寫InitInstance和ExitInstance函數,根據面向對象的多態性,當執行pThread->InitInstance()這一句代碼時執行的函數不再是CWinThread或CWinApp里的InitInstance,而是CDemoADOApp類的InitInstance,我們通過調試工具進入InitInstance內部,圖16示 可以發現,程序果然跳轉到CDemoADOApp類的InitInstance()里面,在InitInstance()里面我們可以對我們的應用程序做初始化工作,當需要的配置都做好之后,退出InitInstance函數,再次回到AfxWinMain函數,接下來程序就會執行Run函數,等待消息響應。圖17示 Win32采用的是消息循環的機制,通過捕捉應用程序上所有消息,識別之后送到相應的消息處理函數去處理操作,MFC也是基于這個機制,不過MFC使用的是消息映射與反射,就是將消息與處理函數通過制定宏建立聯系,歸根到底也是和Win32原理一樣。 調試跟蹤到這里,程序的整體脈絡也大體清晰了,簡單來講AfxWinMain函數內部就執行三個函數InitInstance、Run、ExitInstance,InitInstance初始化,Run循環等待消息并執行相應處理程序,ExitInstance在程序結束之后做收尾工作,如釋放資源等。 我認為學習VC++最重要的是弄清楚MFC的運行機制,弄清楚MFC的運行機制之前先要明白Win32又是怎么工作的,只要明白了Win32的工作流程,理解MFC就會變得簡單很多了,至于其它的開發,都是基于這個運行機制,所以調試分析我沒有對其他窗口的實現進行分析,而是著重分析了應用程序的執行流程。
|