MFC 学习笔记(一):MFC单文档程序运行流程梳理与总结
MFC 學習筆記(一):MFC單文檔程序運行流程梳理與總結
1.MFC單文檔程序運行流程
1.首先利用全局變量對象 theApp 啟動應用程序
(這是因為這個全局對象,基類CWinApp中 this 的指針才能指向這個對象。)
2.調用全局應用程序對象 theApp 的構造函數
(需要先調用其基類CWinApp的構造函數,
完成應用程序的一些初始化工作,并將應用程序對象的指針保存起來。)
3.進入WinMain函數
(CWinApp的構造函數中調用 AfxWinMain 函數)
4.調用虛函數:InitInstance()
(利用在AfxWinMain函數中可以獲取子類的指針,并調用InitInstance函數 如下圖)
(③ 指令實際上調用的是子類(CTestApp)的InitInstance函數)
5.子類(CTestApp)中的InitInstance()函數完成應用程序的一些初始化工作
(包括窗口類的注冊,創建,窗口的顯示和更新。
期間會多次調用CreateEX函數,因為一個單文檔MFC應用程序有多個窗口,包括框架窗口.工具條.狀態條等。)
初始化舉例
例如:
1)CTestApp::Initstance()函數中定義了一個單文檔模板對象指針,
2)該對象就把文檔類對象、框架類對象、視窗類對象有機地組織在一起,
3)接著利用AddDocTemplate函數把這個單文檔模板添加到文檔模板中,從而把這個三個類組織成為一個整體,如圖:
又如:
1)m_pMainWnd 表示指向程序框架窗口的指針(CMainFrame)
2)通過該指針顯示和更新程序框架窗口
等
4.進入消息循環。
上圖:pThread->Run()
(雖然也設置了默認的窗口過程函數,但是,MFC應用程序實際上是采用消息映射機制來處理各種消息。當收到WM_QUIT消息時,退出消息循環,程序結束。)
參考博客:
https://blog.csdn.net/c_base_jin/article/details/52345563
PS:
1.Afx前綴的函數代表應用程序框架(Application Framework)函數,屬于全局函數,它們可以在程序的任何地方被調用。
2.以域作用符“::”開始的表示的函數,表明該函數是一個全局函數。
2.總結補充
1.由于theApp是全局對象,因此會在進入WinMain()之前完成構造
theApp的構造動作會導致一系列的對theApp的初始化動作:
2.接著進入WinMain()
WinMain()(_tWinMain(),這是為了UniCode而準備的一個宏)直接調用AfxWinMain(),AfxWinMain()發揮真正應該由WinMain()發揮的作用,它取得theApp,然后必須先調用AfxWinInit(),再用取得的指向theApp的指針pApp調用InitApplication()、InitInstance()和Run(),最后調用AfxWinTerm()終止程序。
即AfxWinMain()中的動作相當于:
3.AfxWinInit()做什么?
首先將WinMain()傳進來的四個參數保留在theApp的成員變量里。
調用AfxInitThread(),此函數又調用::SetWindowHookEx(),不知干啥。另外此函數還將消息隊列盡量加大到96。
4.CWinApp::InitApplication()做什么?
會做一些與CDocManager()和Document Template相關的工作,是MFC的內部管理范疇。
5.CMyWinApp::InitInstance()做什么?
終于來到了我們可以改寫的InitInstance(),這個函數是CWinApp的虛函數,CMyWinApp通常要改寫它,其實在CWinApp中InitInstance()是一個空函數。
InitInstance()的動作如下:
【(InitInstance()首先會創建一個CMyFrameWnd對象,并將指針保留在m_pMainWnd中。這個CMyFrameWnd對象的創建過程就會導致主窗口的登記和建立,因為CFrameWnd的構造函數中會調用Create()函數,而這個函數負責創建窗口(通過調用CreateWindowEx),窗口風格使用最常見的WS_OVERLAPPEDWINDOW。
但是這僅僅是創建窗口,窗口類注冊的動作(必須先于窗口的創建)又發生在哪里呢?
其實Create()的調用會導致CWnd::CreateEx()的調用,此函數才是真正調用CreateWindowEx()創建窗口者,在調用CreateWindowEx()之前會調用CFrameWnd::PreCreateWindow(),此函數判斷傳入的窗口類名lpszClassName是否為NULL,若是,則通過一系列的調用(非常之繞)為其注冊默認窗口類別。由于每個窗口創建過程中PreCreateWindow()都只在創建之前被調用,因此窗口的注冊大多在創建之前發生。CWnd及其派生類的各個不同)
PreCreateWindow()函數為不同窗口指定了不同的默認窗口類別:
CWnd使用的窗口類別是_afxWnd
CFrameWnd和CMDIChildWnd使用的窗口類別是_afxWndFrameOrView
CMDIFrameWnd使用的窗口類別是_afxWndMDIFrame】
綜上,InitInstance()中的第一個動作――創建CMyFrameWnd對象――完成了窗口的創建。之后的動作就很直觀了,ShowWindow()顯示窗口,UpdateWindow()發送WM_PAINT消息更新窗口。
6.回到AfxWinMain()中,接下來執行的是CWinApp::Run()。
Run()所做的正是維持程序運行的“消息循環”。CWinApp::Run()會調用CWinThread::Run(),此Run()中有消息循環,通過PumpMessage()得到并轉發消息(調用::GetMessage()、::TranslateMessage()、::DispatchMessage(),一如SDK!)。
**但是轉發到哪里呢?窗口函數呢?**原來在MFC為我們注冊默認窗口類的時候已經指定了窗口函數為DefWindowProc(),但是真正處理消息的又不是它,而是一個全局函數AfxWndProc(),這是MFC通過hook和subclassing技術做到的,暫且不提。
綜上,MFC為我們的程序提供了WinMain()、注冊了窗口類、創建了窗口甚至提供了窗口函數,留給我們做的只是寫出響應消息的處理函數,而這些消息和處理函數如何對應起來還要靠MFC六大關鍵技術之一的Message Mapping(消息映射)。消息映射機制的目的是首先搭建起消息和消息處理函數對應的大框架,再通過宏的機制讓程序員能夠方便地添加消息和消息處理函數之間的對應關系。
7.在程序運行的過程中,程序不斷地由消息所驅動,直到用戶動作發出了WM_CLOSE消息,程序即將關閉
過程是:由于CMyFrameWnd沒有設立WM_CLOSE的處理函數,因此該消息被送往預設處理函數,預設函數對WM_CLOSE的處理是調用::DestroyWindow(),進而發送WM_DESTROY消息,WM_DESTROY消息同樣會被送到預設處理函數,預設函數對WM_DESTROY的處理方法是調用::PostQuitMessage(),發送WM_QUIT,CWinApp::Run()在收到WM_QUIT后會結束自己的消息循環,并調用ExitInstance(),這是CWinApp的虛函數,可被CMyWinApp改寫,調用過此函數后,回到AfxWinMain()中調用AfxWinTerm()結束程序。
總結
以上是生活随笔為你收集整理的MFC 学习笔记(一):MFC单文档程序运行流程梳理与总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 暗备用的运行状态_瞧:我利用“无偏二极管
- 下一篇: Halcon学习笔记(一):Qt+Hal