青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

笑看風云淡

寵辱不驚,看庭前花開花落;去留無意,望天空云卷云舒
posts - 96, comments - 48, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 ::  :: 聚合  :: 管理

MFC消息響應機制分析

Posted on 2009-09-15 11:00 天之驕子 閱讀(478) 評論(0)  編輯 收藏 引用

一.引言

VC++的MFC類庫實際上是Windows下C++編程的一套最為流行的類庫。MFC的框架結構大大方便了程序員的編程工作,但是為了更加有效、靈活的使用MFC編程,了解MFC的體系結構往往可以使編程工作事半功倍。它合理的封裝了WIN32 API函數,并設計了一套方便的消息映射機制。但這套機制本身比較龐大和復雜,對它的分析和了解無疑有助于我們寫出更為合理的高效的程序。這里我們簡單的分析MFC的消息響應機制,以了解MFC是如何對Windows的消息加以封裝,方便用戶的開發。

二.SDK下的消息機制實現

這里簡單的回顧一下SDK下我們是如何進行Windows的程序開發的。一般來說,Windows的消息都是和線程相對應的。即Windows會把消息發送給和該消息相對應的線程。在SDK的模式下,程序是通過GetMessage函數從和某個線程相對應的消息隊列里面把消息取出來并放到一個特殊的結構里面,一個消息的結構是一個如下的STRUCTURE。

typedef struct tagMSG {

HWND   hwnd;

UINT   message;

WPARAM wParam;

LPARAM lParam;

DWORD  time;

POINT  pt;

}MSG;

其中hwnd表示和窗口過程相關的窗口的句柄,message表示消息的ID號,wParam和lParam表示和消息相關的參數,time表示消息發送的時間,pt表示消息發送時的鼠標的位置。

然后TranslateMessage函數用來把虛鍵消息翻譯成字符消息并放到響應的消息隊列里面,最后DispatchMessage函數把消息分發到相關的窗口過程。然后窗口過程根據消息的類型對不同的消息進行相關的處理。在SDK編程過程中,用戶需要在窗口過程中分析消息的類型和跟消息一起的參數的含義,做不同的處理,相對比較麻煩,而MFC把消息調用的過程給封裝起來,使用戶能夠通過ClassWizard方便的使用和處理Windows的各種消息。

三.MFC的消息實現機制

我們可以看到,在MFC的框架結構下,可以進行消息處理的類的頭文件里面都會含有DECLARE_MESSAGE_MAP()宏,這里主要進行消息映射和消息處理函數的聲明。可以進行消息處理的類的實現文件里一般都含有如下的結構。

BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)

//{{AFX_MSG_MAP(CInheritClass)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

這里主要進行消息映射的實現和消息處理函數的實現。 

所有能夠進行消息處理的類都是基于CCmdTarget類的,也就是說CCmdTarget類是所有可以進行消息處理類的父類。CCmdTarget類是MFC處理命令消息的基礎和核心。

同時MFC定義了下面的兩個主要結構:

AFX_MSGMAP_ENTRY

struct AFX_MSGMAP_ENTRY

{

UINT nMessage;   // windows message

UINT nCode;  // control code or WM_NOTIFY code

UINT nID;    

// control ID (or 0 for windows messages)

UINT nLastID;   

// used for entries specifying a range of control id's

UINT nSig;       

// signature type (action) or pointer to message #

AFX_PMSG pfn;    // routine to call (or special value)

};

和AFX_MSGMAP

struct AFX_MSGMAP

{

#ifdef _AFXDLL

const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();

#else

const AFX_MSGMAP* pBaseMap;

#endif

const AFX_MSGMAP_ENTRY* lpEntries;

};

其中AFX_MSGMAP_ENTRY結構包含了

一個消息的所有相關信息,其中

nMessage為Windows消息的ID號

nCode為控制消息的通知碼

nID為Windows控制消息的ID

nLastID表示如果是一個指定范圍的消息被映射的話,

nLastID用來表示它的范圍。

nSig表示消息的動作標識

AFX_PMSG pfn 它實際上是一個指向

和該消息相應的執行函數的指針。

而AFX_MSGMAP主要作用是兩個,一:用來得到基類的消息映射入口地址。二:得到本身的消息映射入口地址。

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

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

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

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

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

函數AfxCallWndProc調用CWnd類的方法WindowProc進行消息處理。注意AfxWndProc和AfxCallWndProc都是AFX的API函數。而WindowProc已經是CWnd的一個方法。所以可以注意到在WindowProc中已經沒有關于句柄或者是CWnd的參數了。

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

void CInheritView::OnLButtonDown

(UINT nFlags, CPoint point)

{

// TODO: Add your message

handler code here and/or call default

CView::OnLButtonDown(nFlags, point);

}

注意這里CView::OnLButtonDown(nFlags, point)實際上就是調用CWnd的Default()方法。 而Default()方法所做的工作就是調用DefWindowProc對消息進行處理。這實際上是調用原來的窗口過程進行缺省的消息處理。

如果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(表示鍵值)由小寫字母的值該為大寫字母的值就實現了這個功能。

繼續上面的例子,根據我們對MFC消息機制的分析,我們很容易得到除了上面的方法,我們至少還可以在另外兩個地方進行操作。 

一,在消息的處理方法里面即OnChar中,當然最后我們不再調用CEdit::OnChar(nChar, nRepCnt, nFlags),而是直接調用DefWindowProc(WM_CHAR,nChar,MAKELPARAM (nRepCnt,nFlags))。因為從我們上面的分析可以知道CEdit::OnChar(nChar, nRepCnt, nFlags)實際上也就是對DefWindowProc方法的調用。 

二,我們可以直接重載DefWindowProc方法,對message類型等于WM_CHAR的,直接修改nChar的值即可。

四.小結

通過對MFC類庫的分析和了解,不僅能夠使我們更好的使用MFC類庫,同時,對于我們自己設計和實現框架和類,無疑也有相當大的幫助。


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99www免费人成精品| 91久久综合亚洲鲁鲁五月天| 欧美有码视频| 亚洲欧美激情一区| 亚洲福利一区| 久久精品日韩| 午夜在线精品| 久久精品国产视频| 免费亚洲电影在线观看| 另类亚洲自拍| 欧美日韩岛国| 国产在线一区二区三区四区| 在线观看成人小视频| 亚洲国产另类精品专区| 99riav国产精品| 午夜天堂精品久久久久| 免费观看日韩| 一区二区三区高清在线| 欧美一区国产一区| 欧美激情一二三区| 国产亚洲电影| 亚洲精品免费在线观看| 亚洲在线视频观看| 久久综合中文色婷婷| 亚洲国产精品专区久久| 一区二区高清| 欧美一区二区三区视频免费播放 | 亚洲激情在线观看| 亚洲免费视频中文字幕| 欧美大片免费观看在线观看网站推荐| 亚洲欧洲在线免费| 欧美一级艳片视频免费观看| 欧美激情一区二区三区高清视频| 国产精品免费看片| 亚洲精品日韩激情在线电影| 久久国产一区二区| 日韩午夜高潮| 免费一区二区三区| 国产区日韩欧美| 亚洲在线日韩| 最近中文字幕日韩精品| 久久高清国产| 国产免费成人av| 在线一区二区三区四区| 男人插女人欧美| 久久av红桃一区二区小说| 欧美视频精品在线| 日韩一区二区免费高清| 欧美大色视频| 久久精品99国产精品| 国产精品美女www爽爽爽视频| 日韩五码在线| 亚洲国产精品一区二区尤物区| 久久精品视频在线播放| 国产精品久久久久影院亚瑟| 亚洲视频axxx| 一区二区三区 在线观看视频 | 中文在线一区| 亚洲日本精品国产第一区| 99一区二区| 欧美一区二视频| 亚洲午夜国产成人av电影男同| 欧美日本在线一区| 亚洲国产精品电影在线观看| 久久久精彩视频| 亚洲男人的天堂在线aⅴ视频| 国产精品v欧美精品∨日韩| 一区二区三区欧美激情| 亚洲免费不卡| 国产精品v日韩精品v欧美精品网站| 一区二区三区国产精华| 一区二区三区欧美视频| 久久久久久久综合色一本| 国产欧美日本| 亚洲私人影吧| 99精品免费| 国产精品久久精品日日| 亚洲男人天堂2024| 亚洲欧美日韩在线不卡| 国内精品久久久久久久影视蜜臀| 久久精品一区中文字幕| 久久av免费一区| 日韩午夜激情| 制服丝袜激情欧洲亚洲| 国产日韩欧美综合| 欧美国产精品v| 欧美午夜一区二区福利视频| 性8sex亚洲区入口| 久久久久一区二区| 一区二区三区视频在线| 午夜国产精品视频| 亚洲高清视频一区| 99re6热在线精品视频播放速度| 国产欧美日韩精品丝袜高跟鞋 | 性欧美激情精品| 久久久久久久久久久一区| 亚洲另类春色国产| 亚洲一区二区精品| 亚洲国产一区二区视频| 亚洲视频国产视频| 亚洲国产精品黑人久久久| 一区二区三区高清不卡| 亚洲高清中文字幕| 亚洲一级高清| 亚洲人成网站精品片在线观看| 亚洲一区二区高清视频| 亚洲精选在线| 久久九九国产精品| 亚洲欧美日韩综合| 免费欧美在线| 久久一二三区| 国产精品久久久久久影院8一贰佰| 麻豆精品视频在线观看视频| 欧美日韩在线一区| 欧美国产精品人人做人人爱| 国产乱码精品一区二区三区不卡 | 国产精品免费小视频| 国产精品a久久久久久| 一本大道av伊人久久综合| 亚洲欧美一区二区三区在线| 99re6热在线精品视频播放速度| 亚洲女人天堂av| 亚洲视频免费在线| 欧美喷水视频| 欧美国产国产综合| 亚洲高清视频在线| 久久影视三级福利片| 久久久久久久久久码影片| 国产精品揄拍500视频| 99re6热在线精品视频播放速度 | 小处雏高清一区二区三区| 欧美精品v国产精品v日韩精品 | 黄色精品免费| 欧美一区三区二区在线观看| 中文网丁香综合网| 欧美日韩不卡| 一本色道久久综合亚洲二区三区 | 欧美午夜www高清视频| 亚洲电影成人| 亚洲欧洲视频| 欧美精品国产精品| 亚洲精品一区久久久久久| 亚洲人成免费| 欧美国产综合视频| 亚洲精品激情| 亚洲一区二区毛片| 国产精品视频xxx| 欧美亚洲自偷自偷| 久久亚洲春色中文字幕久久久| 国产视频亚洲精品| 久久九九热免费视频| 欧美阿v一级看视频| 亚洲精选在线观看| 欧美午夜www高清视频| 日韩一区二区久久| 午夜在线视频一区二区区别| 国产日韩欧美精品| 久久国产欧美日韩精品| 欧美激情第10页| 亚洲在线视频免费观看| 国产综合久久久久久| 久久只有精品| 一区二区三区黄色| 欧美综合激情网| 亚洲国产成人久久综合| 欧美人与禽性xxxxx杂性| 午夜在线观看免费一区| 裸体丰满少妇做受久久99精品| 亚洲黄色性网站| 国产精品不卡在线| 久久久噜噜噜久久| 一区二区三区成人| 美国十次了思思久久精品导航| 日韩一级片网址| 国产一区日韩欧美| 欧美特黄一区| 欧美在线观看一区二区| 一区免费在线| 国产精品狼人久久影院观看方式| 亚洲欧美高清| 久久亚洲综合色| 欧美综合77777色婷婷| 美国十次成人| 中文在线一区| 亚洲第一区在线| 国产美女精品| 欧美激情黄色片| 久久国产一区| 亚洲午夜久久久久久久久电影院| 能在线观看的日韩av| 午夜精品久久久久久久蜜桃app| 亚洲电影免费观看高清完整版在线观看 | 欧美大片免费| 欧美一区二视频| 亚洲午夜影视影院在线观看| 欧美黑人国产人伦爽爽爽| 久久成人一区| 亚洲欧美日韩视频二区| 亚洲精品在线看| 在线观看日韩av先锋影音电影院|