1. 程式人生 > >VS2013/MFC程式設計入門之三(MFC應用程式框架分析)

VS2013/MFC程式設計入門之三(MFC應用程式框架分析)

  上一講講的是VS2013應用程式工程中檔案的組成結構。這一節就為大家分析下MFC應用程式框架的執行流程。

       一.SDK應用程式與MFC應用程式執行過程的對比

       程式執行都要有入口函式,在之前的C++教程中都是main函式,而Windows應用程式的入口函式是WinMain函式,MFC程式也是從WinMain函式開始的。下面就給出用Windows SDK寫的“HelloWorld”程式,與應用程式框架進行對比,這樣能更好的瞭解框架是怎樣執行的。Windows SDK開發程式就是不使用MFC類庫,直接用Windows API函式進行軟體開發。本講不是要講解SDK開發,只是為了對比而簡單介紹,至於SDK開發可以在大家學完MFC以後選擇是否要研究,一般來說有簡單瞭解就可以了。

       SDK應用程式

       首先,給出Windows SDK應用程式“HelloWorld”的原始碼:  

C++程式碼
  1. #include <windows.h>  
  2. LRESULT CALLBACK myWndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam);   
  3. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)      
  4. {      
  5. const
    staticTCHAR appName[] = TEXT("Hello world");      
  6.   WNDCLASSEX myWin;      
  7.   myWin.cbSize = sizeof(myWin);      
  8.   myWin.style = CS_HREDRAW | CS_VREDRAW;      
  9.   myWin.lpfnWndProc = myWndProc;      
  10.   myWin.cbClsExtra = 0;      
  11.   myWin.cbWndExtra = 0;      
  12.   myWin.hInstance = hInstance;      
  13.   myWin.hIcon = 0;      
  14.   myWin.hIconSm  = 0;      
  15.   myWin.hCursor = 0;      
  16.   myWin.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);      
  17.   myWin.lpszMenuName = 0;      
  18.   myWin.lpszClassName = appName;      
  19. //Register    
  20. if (!RegisterClassEx(&myWin)) return 0;      
  21. constHWND hWindow = CreateWindow(      
  22.     appName,      
  23.     appName,      
  24.     WS_OVERLAPPEDWINDOW,      
  25.     CW_USEDEFAULT,      
  26.     CW_USEDEFAULT,      
  27.     CW_USEDEFAULT,      
  28.     CW_USEDEFAULT,      
  29.     0,      
  30.     0,      
  31.     hInstance,      
  32.     0);      
  33.   ShowWindow(hWindow,iCmdShow);      
  34.   UpdateWindow(hWindow);      
  35.   {      
  36.     MSG msg;      
  37. while(GetMessage(&msg,0,0,0))      
  38.     {      
  39.       TranslateMessage(&msg);      
  40.       DispatchMessage(&msg);      
  41.     }      
  42. return (int)msg.wParam;      
  43.   }      
  44. }      
  45. LRESULT CALLBACK myWndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)      
  46. {      
  47. if (msg==WM_PAINT)      
  48.   {      
  49.     PAINTSTRUCT ps;      
  50. constHDC hDC = BeginPaint(hWindow,&ps);      
  51.     RECT rect;      
  52.     GetClientRect(hWindow,&rect);      
  53.     DrawText(hDC,TEXT("HELLO WORLD"),-1,&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);      
  54.     EndPaint(hWindow,&ps);      
  55. return 0;      
  56.   }      
  57. elseif (msg==WM_DESTROY)      
  58.   {      
  59.     PostQuitMessage(0);      
  60. return 0;      
  61.   }      
  62. return DefWindowProc(hWindow,msg,wParam,lParam);      
  63. }  

       上面的程式執行的流程是:進入WinMain函式->初始化WNDCLASSEX,呼叫RegisterClassEx函式註冊視窗類->呼叫ShowWindow和UpdateWindow函式顯示並更新視窗->進入訊息迴圈。關於訊息迴圈再簡單說下,Windows應用程式是訊息驅動的,系統或使用者讓應用程式進行某項操作或完成某個任務時會發送訊息,進入程式的訊息佇列,然後訊息迴圈會將訊息佇列中的訊息取出,交予相應的視窗過程處理,此程式的視窗過程函式就是myWndProc函式,視窗過程函式處理完訊息就完成了某項操作或任務。本例是要顯示“HELLO WORLD”字串,UpdateWindow函式會發送WM_PAINT訊息,但是此訊息不經過訊息佇列而是直接送到視窗過程處理,在視窗過程函式中最終繪製了“HELLO WORLD”字串。

       MFC應用程式

       下面是MFC應用程式的執行流程,通過MFC庫中程式碼進行分析:

       首先在HelloWorld.cpp中定義全域性物件theApp:CHelloWorldApp theApp;。呼叫CWinApp和CHelloWorldApp的建構函式後,進入WinMain函式(位於appmodul.cpp中)。

C++程式碼
  1. extern"C"int WINAPI   
  2. _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,   
  3.     _In_ LPTSTR lpCmdLine, int nCmdShow)   
  4. #pragma warning(suppress: 4985) 
  5. {   
  6. // call shared/exported WinMain 
  7. return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);   
  8. }  

       在TCHAR.h中,有此定義:#define _tWinMainWinMain,所以這裡的_tWinMain就是WinMain函式。它呼叫了AfxWinMain函式(位於WinMain.cpp中)。

C++程式碼
  1. int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)   
  2. {    
  3.        .............略   
  4. // App global initializations (rare) 
  5. if (pApp != NULL && !pApp->InitApplication())   
  6. goto InitFailure;   
  7. if (!pThread->InitInstance())   
  8.        {   
  9.               .........略   
  10.        }   
  11. // Run函式位於THRDCORE.cpp中,由此函式進入訊息迴圈 
  12.        nReturnCode = pThread->Run();   
  13.        ..............略   
  14. return nReturnCode;   
  15. }   

       上面InitInstance函式的程式碼如下:

C++程式碼
  1. BOOL CTestApp::InitInstance()        
  2. {       
  3.        .............略       
  4.        CSingleDocTemplate* pDocTemplate;       
  5.        pDocTemplate = new CSingleDocTemplate(       
  6.               IDR_MAINFRAME,       
  7.               RUNTIME_CLASS(CTestDoc),       
  8.               RUNTIME_CLASS(CMainFrame),      // main SDI frame window     
  9.               RUNTIME_CLASS(CTestView));     
  10. if (!pDocTemplate)   
  11. return FALSE;     
  12.        AddDocTemplate(pDocTemplate);       
  13. // Parse command line for standard shell commands, DDE, file open     
  14.        CCommandLineInfo cmdInfo;       
  15.        ParseCommandLine(cmdInfo);       
  16. //ProcessShellCommand位於AppUI2.cpp中,註冊並建立視窗     
  17. if (!ProcessShellCommand(cmdInfo))       
  18. return FALSE;       
  19.        m_pMainWnd->ShowWindow(SW_SHOW);       
  20.        m_pMainWnd->UpdateWindow();       
  21. return TRUE;       
  22. }      

       InitInstance中的ProcessShellCommand函式又呼叫了CMainFrame的LoadFrame函式註冊並建立了視窗,執行完ProcessShellCommand函式以後,呼叫了m_pMainWnd的ShowWindow和UpdateWindow函式顯示並更新框架視窗。這些是不是與上面的SDK程式十分類似?

       接下來該是訊息迴圈了,上面的AfxWinMain函式中呼叫了pThread的Run函式(位於THRDCORE.cpp中),在Run中包含了訊息迴圈。Run函式的程式碼如下:

C++程式碼
  1. int CWinThread::Run()       
  2. {       
  3.         .............略       
  4. // phase2: pump messages while available     
  5. do
  6.         {       
  7. // pump message, but quit on WM_QUIT     
  8. if (!PumpMessage())       
  9. return ExitInstance();       
  10. // reset "no idle" state after pumping "normal" message     
  11. if (IsIdleMessage(&m_msgCur))       
  12.               {       
  13.                      bIdle = TRUE;       
  14.                      lIdleCount = 0;       
  15.               }       
  16.        } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));       
  17.        ..............略       
  18. }       
  19. BOOL CWinThread::PumpMessage()       
  20. {     
  21. return AfxInternalPumpMessage();    
  22. }    
  23. BOOL AFXAPI AfxInternalPumpMessage()   
  24. {   
  25.        _AFX_THREAD_STATE *pState = AfxGetThreadState();   
  26. if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))          
  27.        {       
  28.              .............略       
  29.        }       
  30.        ...............略       
  31. if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))   
  32.        {   
  33.              ::TranslateMessage(&(pState->m_msgCur));   
  34.              ::DispatchMessage(&(pState->m_msgCur));   
  35.        }     
  36. return TRUE;       
  37. }       

       我們看到PumpMessage中通過呼叫GetMessage、TranslateMessage、DispatchMessage等建立了訊息迴圈並投遞訊息。

       視窗過程函式AfxWinProc形式如下:

C++程式碼
  1. LRESULT CALLBACK AfxWndProc(HWND hWnd,UINT nMsg,WPARAM wParam, LPARAM lParam)   
  2. {   
  3.       ……   
  4.       CWnd*pWnd=CWnd::FromHandlePermanent(hWnd);
  5.       ReturnAfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);   
  6. }  

兩者執行過程對比

       到此,通過對比可以發現,MFC應用程式的執行流程與SDK程式是類似的,都是先進行一些初始化過程,再註冊並建立視窗,然後顯示、更新視窗,最後進入訊息迴圈,訊息都由視窗過程函式處理。現在大家是不是覺得有些頭緒了?在執行流程上有基本的掌握即可。

二.MFC應用程式框架主要類之間的關係

       在第一講中,給大家演示瞭如何利用應用程式嚮導生成單文件應用程式框架,可以看到程式的基本框架和必要的程式碼都自動生成了,上一講又講解了檔案組成結構,實際上在前面自動生成的框架中比較重要的類包括以下幾個:CHelloWorldApp、CMainFrame、CHelloWorldDoc和CHelloWorldView,至於其他的類比如CClassView、CFileView等都是在框架視窗(CMainFrame)上建立的面板等,不是必要的。

       就四個主要類的關係簡單講下,CHelloWorldApp類處理訊息,將收到的訊息分發給相應的物件。CMainFrame是檢視CHelloWorldView的父視窗,檢視CHelloWorldView就顯示在CMainFrame的客戶區中。檢視類CHelloWorldView用來顯示文件類CHelloWorldDoc中的資料,並根據對檢視類的操作修改文件類的資料。一個檢視類只能跟一個文件類相聯絡,而一個文件類可以跟多個檢視類相聯絡。關於檢視類和文件類的關係後面會詳細講解。

       本節VC++/MFC程式設計入門教程內容比較多,主要是讓大家對MFC應用程式的執行原理有大概的瞭解。對於以後的MFC開發有很多好處。如果有問題請在部落格留言交流。謝謝。

相關推薦

VS2013/MFC程式設計入門MFC應用程式框架分析

  上一講講的是VS2013應用程式工程中檔案的組成結構。這一節就為大家分析下MFC應用程式框架的執行流程。        一.SDK應用程式與MFC應用程式執行過程的對比        程式執行都要有入口函式,在之前的C++教程中都是main函式,而Windows應

VS2013/MFC程式設計入門十二選單:VS2013選單資源詳解

前面我們已經講完了所有的常用控制元件,本節開始為大家講解選單的概念及使用。        選單簡介        選單可以分為下拉式選單和彈出式選單。        下拉式選單一般在視窗標題欄下面顯示,大家還記得我們在VS2013/MFC程式設計入門之一(利用MFC

VS2013/MFC程式設計入門十一常用控制元件:標籤控制元件Tab Control

前面兩節講了樹形控制元件Tree Control,本節開始講解標籤控制元件Tab Control,也可以稱為選項卡控制元件。        標籤控制元件簡介        標籤控制元件也比較常見。它可以把多個頁面整合到一個視窗中,每個頁面對應一個標籤,使用者點選某個標

VS2013/MFC程式設計入門對話方塊:為對話方塊新增控制元件

建立對話方塊資源需要建立對話方塊模板、修改對話方塊屬性、為對話方塊新增各種控制元件等步驟,前面一講中已經講了建立對話方塊模板和修改對話方塊屬性,本節繼續講如何為對話方塊新增控制元件。        上一講中建立了一個名為“Addition”的工程,目的是生成一個實現加法

VS2013/MFC程式設計入門對話方塊:建立對話方塊類和新增控制元件變數

前兩講中為大家講解了如何建立對話方塊資源。建立好對話方塊資源後要做的就是生成對話方塊類了。再宣告下,生成對話方塊類主要包括新建對話方塊類、新增控制元件變數和控制元件的訊息處理函式等。        因為給大家的例程Addition是基於對話方塊的程式,所以程式自動建立了

VS2013/MFC程式設計入門二十六常用控制元件:圖片控制元件Picture Control

本節主要講一種簡單實用的控制元件,圖片控制元件Picture Control。通過使用圖片控制元件我們可以在介面某個位置顯示圖片以美化介面。        圖片控制元件簡介        圖片控制元件和前面講到的靜態文字框都是靜態文字控制元件,因此兩者的使用方法有很多

VS2013/MFC程式設計入門十九常用控制元件:靜態文字框

       從本節開始講解各種常用控制元件的用法。MFC中常用控制元件主要包括:靜態文字框、編輯框、單選按鈕、複選框、分組框、列表框、組合框、圖片控制元件、列表控制元件、樹形控制元件和進度條控制元件等等。本節先來講解靜態文字框的使用。        控制元件的通知訊息

VS2013/MFC程式設計入門十六對話方塊:檔案對話方塊

上一講介紹的是訊息對話方塊,本節講解檔案對話方塊。        檔案對話方塊的分類 檔案對話方塊分為開啟檔案對話方塊和儲存檔案對話方塊,相信大家在Windows系統中經常見到這兩種檔案對話方塊。例如,很多編輯軟體像記事本等都有“開啟”選項,選擇“開啟”後會彈出一個對

VS2013/MFC程式設計入門二十七常用控制元件:列表檢視控制元件List Control 上

      本節為大家詳解列表檢視控制元件List Control的使用。      列表檢視控制元件簡介        列表檢視控制元件List Control同樣比較常見,它能夠把任何字串內容以列表的方式顯示出來,這種顯示方式的特點是整潔、直觀,在實際應用中能為使

VS2013/MFC程式設計入門十二對話方塊:屬性頁對話方塊及相關類的介紹

本節開始講一種特殊的對話方塊--屬性頁對話方塊。        屬性頁對話方塊的分類        屬性頁對話方塊想必大家並不陌生,XP系統中桌面右鍵點屬性,彈出的就是屬性頁對話方塊,它通過標籤切換各個頁面。另外,我們在建立MFC工程時使用的嚮導對話方塊也屬於屬性頁對

VS2013/MFC程式設計入門二十三常用控制元件:列表框控制元件ListBox

前面兩節講了比較常用的按鈕控制元件,並通過按鈕控制元件例項說明了具體用法。本文要講的是列表框控制元件(ListBox)及其使用例項。        列表框控制元件簡介        列表框給出了一個選項清單,允許使用者從中進行單項或多項選擇,被選中的項會高亮顯示。列表

VS2013/MFC程式設計入門十五對話方塊:訊息對話方塊

       本節講解Windows系統中最常用最簡單的一類對話方塊--訊息對話方塊。        我們在使用Windows系統的過程中經常會見到訊息對話方塊,提示我們有異常發生或提出詢問等。因為在軟體開發中經常用到訊息對話方塊,所以MFC提供了兩個函式可以直接生成指

VS2013/MFC程式設計入門二十四常用控制元件:組合框控制元件Combo Box

 上一節講了列表框控制元件ListBox的使用,本節主要講解組合框控制元件Combo Box。組合框同樣相當常見,例如,在Windows系統的控制面板上設定語言或位置時,有很多選項,用來進行選擇的控制元件就是組合框控制元件。        組合框控制元件簡介     

VS2013/MFC程式設計入門十一對話方塊:非模態對話方塊的建立及顯示

 上一節講了模態對話方塊及其彈出過程,本節接著講另一種對話方塊--非模態對話方塊的建立及顯示。        前面已經說過,非模態對話方塊顯示後,程式其他視窗仍能正常執行,可以響應使用者輸入,還可以相互切換。本文中將上一講中建立的Tip模態對話方塊改為非模態對話方塊,讓

VS2010/MFC程式設計入門四十三MFC常用類:CTime類和CTimeSpan類

轉載:   http://www.jizhuomi.com/software/230.html 上一節中雞啄米講了MFC常用類CString類的用法,本節繼續講另外兩個MFC常用類-日期和時間類CTime類和CTimeSpan類。    

VS2010/MFC程式設計入門前言

     VC++簡介       VC++全稱是Visual C++,是由微軟提供的C++開發工具,它與C++的根本區別就在於,C++是語言,而VC++是用C++語言編寫程式的工具平臺。VC++不僅是一個編譯器更是一個整合開發環境,包括編輯器、偵錯程式和編譯器等,一般它包含

python程式設計入門條件和迴圈

第三章 條件和迴圈 3.1 改進數字遊戲—if語句 還記不記得我們在第一章開始就寫好的一個“小遊戲”,我們把它再列出來看看。 # ----猜數字遊戲---- num = input("猜猜我心裡想的是哪個數字?") guess = int(num) if g

Python零基礎入門---for迴圈+列表

Python的for迴圈與C、C++等語言的for迴圈的結構還是有很大的差別的,不過還是很容易上手的,Python的列表類似於C語言中的陣列,但是相比陣列的功能更加強大,玩笑話是說打了激素中的陣列。 For迴圈 (1)For迴圈的語法結構: For

Spring Boot入門系列資源文件屬性配置

response mage 註意 site spa website 圖片 process ram   Spring Boot 資源文件屬性配置     配置文件是指在resources根目錄下的application.properties或application.yml配置

Spring原始碼解析自定義標籤的解析

自定義標籤的解析 1、概述:通過前面的文章我們分析了預設標籤的解析,我們先回顧下自定義標籤解析所使用的方法 /** * Parse the elements at the root level in the document: * "import", "alias", "bean".