首頁 > 文章中心 > 正文

      MFC程序設計思考

      前言:本站為你精心整理了MFC程序設計思考范文,希望能為你的創作提供參考價值,我們的客服老師可以幫助你提供個性化的參考范文,歡迎咨詢。

      MFC程序設計思考

      摘要:mfc以層次結構組織起來,比較龐雜,尤其是它的消息映射機制,更是涉及到很多底層的東西。本文通過對整個消息映射機制進行系統的分析,可以幫助程序開發人員更好地了解MFC,進行可視化編程。

      關鍵詞:消息驅動;消息映射;MFC程序設計

      1引言

      微軟公司提供的MFC基本類庫(MicrosoftFoundationClasses),是進行可視化編程時使用最為流行的一個類庫。MFC封裝了大部分WindowsAPI函數和Windows控件,使得程序的開發變得簡單,極大的縮短了程序的開發周期。MFC獨創的Document/View框架結構,能夠將管理數據的代碼和顯示數據的程序代碼分開,并且設計了一套方便的消息映射和命令傳遞機制,方便程序員的開發使用。其中消息映射機制本身比較龐大和復雜,對它的分析和了解無疑有助于我們寫出更為合理的高效的程序。這里我們分析一下MFC的消息映射機制,以了解MFC是如何對Windows的消息加以封裝,方便用戶的開發。

      2SDK下的消息機制實現

      首先,簡單回顧一下SDK下我們是如何進行Windows的程序開發的。Windows程序的運行是依靠外部發生的事件來驅動的,事件由操作系統捕捉,以消息的形式進入消息隊列,然后通過消息循環從隊列中不斷取出消息,送到對應的窗口過程里處理。相對于DOS程序,Windows是以WinMain作為程序的入口點,以下就是一個簡化的Win32程序的主體,通過while語句實現消息循環:

      WinMain(…)

      {

      MSGmsg;

      RegisterClass(…);//注冊窗口類

      CreateWindow(…);//創建窗口

      ShowWindow(…);//顯示窗口

      UpdateWindow(…);

      While(GetMessage(&msg,…)){//消息循環

      TranslateMessage(…);

      DispatchMessage(…);

      }

      returnmsg.wParam;

      }

      其中,msg代表消息,程序是通過GetMessage函數從和某個線程相對應的消息隊列里面把消息取出來并放到消息變量msg里面。然后TranslateMessage函數用來把鍵盤消息轉化并放到響應的消息隊列里面,最后DispatchMessage函數把消息分發到相關的窗口過程去處理。窗口過程根據消息的類型對不同的消息進行相關的處理。在SDK編程過程中,用戶需要在窗口過程中分析消息的類型及其參數的含義,然后做不同的處理,相對比較麻煩;而MFC把消息調用的過程給封裝起來,使用戶能夠通過ClassWizard方便的使用和處理Windows的各種消息。

      3MFC中的消息映射機制

      在MFC的框架結構下,“消息映射”是通過巧妙的宏定義,形成一張消息映射表格來進行的。這樣一旦消息發生,Framework就可以根據消息映射表格來進行消息映射和命令傳遞。

      首先在需要進行消息處理的類的頭文件(.H)里,都會含有DECLARE_MESSAGE_MAP()宏,聲明該類擁有消息映射表格:

      classCscribbleDoc:publicCdocument

      {

      DECLARE_MESSAGE_MAP()

      };

      然后在類應用程序文件(.CPP)實現這一表格

      BEGIN_MESSAGE_MAP(CInheritClass,CBaseClass)

      //{{AFX_MSG_MAP(CInheritClass)

      ON_COMMAND(ID_EDIT_COPY,OnEditCopy)

      ………

      //}}AFX_MSG_MAP

      END_MESSAGE_MAP()

      ----這里主要進行消息映射的實現,把它和消息處理函數聯系在一起。其中出現三個宏,第一個宏是BEGIN_MESSAGE_MAP有兩個參數,分別是擁有消息表格的類,及其父類。第二個宏是ON_COMMAND,指定命令消息的處理函數名稱。第三個宏是END_MESSAGE_MAP()作為結尾符號。中間的奇怪符號//}}和//{{,是ClassWizard產生的,對程序無影響。

      觀察DECLARE_MESSAGE_MAP的定義:

      #defineDECLARE_MESSAGE_MAP()

      private:

      staticconstAFX_MESSAGE_ENTRY_messageEntries[];

      protected:

      staticAFX_DATAconstAFX_MSGMAPmessageMap;

      virtualconstAFX_MSGMAP*GetMessageMap()const;

      里面又包含了MFC新定義的兩個數據結構,如下:

      AFX_MSGMAP_ENTRY

      structAFX_MSGMAP_ENTRY

      {

      UINTnMessage;//windowsmessage

      UINTnCode;//controlcodeorWM_NOTIFYcode

      UINTnID;//controlID(or0forwindowsmessages)

      UINTnLastID;//usedforentriesspecifyingarangeofcontrolid''''s

      UINTnSig;//signaturetype(action)orpointertomessage#

      AFX_PMSGpfn;//routinetocall(orspecialvalue)

      };

      和AFX_MSGMAP

      structAFX_MSGMAP

      {

      constAFX_MSGMAP*pBaseMap;

      constAFX_MSGMAP_ENTRY*lpEntries;

      };

      其中AFX_MSGMAP_ENTRY結構包含了一個消息的所有相關信息,而AFX_MSGMAP主要作用有兩個,一是用來得到基類的消息映射入口地址。二是得到本身的消息映射入口地址。

      實際上,MFC把所有的消息一條條填入到AFX_MSGMAP_ENTRY結構中去,形成一個數組,該數組存放了所有的消息和與它們相關的參數。同時通過AFX_MSGMAP能得到該數組的首地址,同時得到基類的消息映射入口地址。當本身對該消息不響應的時候,就可以上溯到基類的消息映射表尋找對應的消息響應。

      現在我們來分析MFC是如何讓窗口過程來處理消息的,實際上所有MFC的窗口類都通過鉤子函數_AfxCbtFilterHook截獲消息,并且在鉤子函數_AfxCbtFilterHook中把窗口過程設定為AfxWndProc。原來的窗口過程保存在成員變量m_pfnSuper中。

      在MFC框架下,一般一個消息的處理過程是這樣的。

      (1)函數AfxWndProc接收Windows操作系統發送的消息。

      (2)函數AfxWndProc調用函數AfxCallWndProc進行消息處理,這里一個進步是把對句柄的操作轉換成對CWnd對象的操作。

      (3)函數AfxCallWndProc調用CWnd類的方法WindowProc進行消息處理。

      (4)WindowProc調用OnWndMsg進行正式的消息處理,即把消息派送到相關的方法中去處理。在CWnd類中都保存了一個AFX_MSGMAP的結構,而在AFX_MSGMAP結構中保存有所有我們用ClassWizard生成的消息的數組的入口,我們把傳給OnWndMsg的message和數組中的所有的message進行比較,找到匹配的那一個消息。實際上系統是通過函數AfxFindMessageEntry來實現的。找到了那個message,實際上我們就得到一個AFX_MSGMAP_ENTRY結構,而我們在上面已經提到AFX_MSGMAP_ENTRY保存了和該消息相關的所有信息,其中主要是消息的動作標識和相關的執行函數。然后我們就可以根據消息的動作標識調用相關的執行函數,而這個執行函數實際上就是通過ClassWizard在類實現中定義的一個方法。這樣就把消息的處理轉化到類中的一個方法的實現上。

      (5)如果OnWndMsg方法沒有對消息進行處理的話,就調用DefWindowProc對消息進行處理。這是實際上是調用原來的窗口過程進行缺省的消息處理。所以如果正常的消息處理的話,MFC窗口類是完全脫離了原來的窗口過程,用自己的一套體系結構實現消息的映射和處理。即先調用MFC窗口類掛上去的窗口過程,再調用原先的窗口過程。用戶面對的消息參數將不再是固定的wParam和lParam,而是和消息類型具體相關的參數。比如和消息WM_LButtonDown相對應的方法OnLButtonDown的兩個參數是nFlags和point。nFlags表示在按下鼠標左鍵的時候是否有其他虛擬鍵按下,point更簡單,就是表示鼠標的位置。同時MFC窗口類消息傳遞中還提供了兩個函數,分別為WalkPreTranslateTree和PreTranslateMessage。我們知道利用MFC框架生成的程序,都是從CWinApp開始執行的,而CWinapp實際繼承了CWinThread類。在CWinThread的運行過程中會調用窗口類中的WalkPreTranslateTree方法。而WalkPreTranslateTree方法實際上就是從當前窗口開始查找愿意進行消息翻譯的類,直到找到窗口沒有父類為止。在WalkPreTranslateTree方法中調用了PreTranslateMessage方法。實際上PreTranslateMessage最大的好處是我們在消息處理前可以在這個方法里面先做一些事情。舉一個簡單的例子,比如我們希望在一個CEdit對象里,把所有的輸入的字母都以大寫的形式出現。我們只需要在PreTranslateMessage方法中判斷message是否為WM_CHAR,如果是的話,把wParam(表示鍵值)由小寫字母的值該為大寫字母的值就實現了這個功能。

      4小結

      MFC通過巧妙的宏定義把消息調用的過程給封裝起來,使用戶能夠通過ClassWizard方便的使用和處理Windows的各種消息。通過對MFC消息映射機制的分析,不僅能夠使我們更好的使用MFC類庫,同時,對于我們自己設計程序框架和類,無疑也有相當大的幫助。

      參考文獻:

      [1]侯俊杰著,深入淺出MFC(第2版)[M].湖北:華中科技大學出版社,2001.5

      [2]DavidJ.Kruglinski著,VisualC++技術內幕(第五版)[M].北京:北京希望電子出版社,2001.1

      文檔上傳者
      亚洲福利视频网站| 国产亚洲情侣一区二区无码AV | 亚洲国产天堂久久久久久| 亚洲精品乱码久久久久久V| 亚洲国产系列一区二区三区| 美女视频黄免费亚洲| 亚洲影院天堂中文av色| 亚洲一卡一卡二新区无人区| 亚洲中文字幕无码爆乳| 亚洲欧美aⅴ在线资源| 亚洲а∨精品天堂在线| 国产精品国产亚洲区艳妇糸列短篇| 亚洲精品无码人妻无码| 亚洲av永久无码精品秋霞电影秋| 亚洲欧美成aⅴ人在线观看| 色欲色欲天天天www亚洲伊| 欧美亚洲精品一区二区| 国产成人亚洲毛片| AV在线亚洲男人的天堂| 国产亚洲3p无码一区二区| 亚洲av日韩av高潮潮喷无码| 亚洲天堂久久精品| 亚洲最新中文字幕| 亚洲中文字幕无码av永久| 久久水蜜桃亚洲AV无码精品| 亚洲高清视频一视频二视频三| 久久久久亚洲精品无码网址 | 亚洲一区二区女搞男| 亚洲国产精品成人久久| 久久av无码专区亚洲av桃花岛 | 久久精品熟女亚洲av麻豆| 亚洲av无码不卡私人影院| 91麻豆精品国产自产在线观看亚洲| 国产亚洲高清不卡在线观看| 久久久久久亚洲AV无码专区| jlzzjlzz亚洲jzjzjz| 亚洲AV无码一区二区三区牲色| 亚洲欧洲精品成人久久奇米网 | 婷婷亚洲综合五月天小说| 亚洲国产亚洲综合在线尤物| 亚洲精品精华液一区二区|