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

大龍的博客

常用鏈接

統計

最新評論

消息如何流動 ----------- 注意 GetMessageMap為虛函數

 一、傳統SDK程序的消息循環

在傳統的SDK程序中,消息循環是很簡單的,也許你不信,那我們就看看下面這段代碼吧:
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
WNDCLAS	wndclass ;
wndclass.style	  = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc  = WndProc ;
wndclass.lpszClassName	= szAppName ;
RegisterClass (&wndclass);
hwnd = CreateWindow( szAppName,……,NULL);
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
………
case WM_PAINT:
………
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
  在WinMain 中 CreateWindow通過一個參數將創建的窗口和窗口類(見"窗口類的誕生"一文)聯系起來,這樣該窗口的所有消息都將發送到該窗口類的窗口函數WndProc,其后WndProc根據不同的消息給予不同的動作。

二、MFC期望的消息循環
  在傳統的SDK程序中消息循環是非常簡單的,并且將窗口和窗口函數綁定在一起。而在MFC中就出現了問題,比如CDocument類,不是窗口,所以沒有窗口類,但是我也想讓它響應消息,怎辦?問題不僅僅如此,我們再看看MFC的消息,就會發現更多問題。
  MFC將消息分為三大類:1.標準消息,即除WM_COMMAND之外的任何WM_開頭的消息,任何派生自CWnd的類都可以接受該消息,并按照繼承關系接受(如從CScrollView到CView再到CWnd)。2.命令消息,即WM_COMMAND,任何派生自CCmdTarget的類,兼可接受該消息,接受順序如下圖所示,其中標號標注了接受消息的順序,箭頭代表調用順序 :


圖1 消息的拐彎流動

3.Control Notification,通知類消息,也以WM_COMMAND形式出現,由控件產生,通知其父窗口。

三、消息宏背后的秘密
  知道了MFC消息流動的要求,那MFC是怎樣實現的呢?當一個消息出現時,Application FrameWork怎么知道將該消息發送給哪個對象的呢?其實都是CCmdTarget類在作怪,所有能夠接受消息的類都必須繼承于CCmdTarget類,因為這些類都一個共同的特征:含有DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、END_MESSAGE_MAP三個宏。啊!就這三個宏組織了一張龐大的消息映射網,也許你不信,那我們就看看這三個宏是怎樣定義的:
#define DECLARE_MESSAGE_MAP()\
private:\
static const AFX_MSGMAP_ENTRY _messageEntries[];\
protected:
static AFX_DATA const AFX_MSGMAP messageMap;\
virtual const AFX_MSGMAP* GetMessageMap() const;\
#define BEGIN_MESSAGE_MAP(theClass, baseClass)\
const AFX_MSGMAP* theClass::GetMessageMap() const\
{return &theClass::messageMap;}\
AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \
{&baseClass::messageMap, &theClass::_messageEntries[0]};\
const AFX_MSGMAP_ENTRY theClass::_messageEntries[]=\
{\
#define END_MESSAGE_MAP()\
{0,0,0,0,AfxSig_end,(AFX_pMSG)0}\
};\
typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
struct AFX_MSGMAP_ENTRY
{
UINT  nMessage;
UINT  nCode;
UINT  nID;
UINT  nLastID;
UINT  nSig;
AFX_PMSG pfn;
};
struct AFX_MSGMAP
{
const AFX_MSGMAP* pBaseMap;
const AFX_MSGMAP_ENTRY* lpEntries;
};
  可以看出DECLARE_MESSAGE_MAP宏在其類中申請了一個全局結構和獲得該結構的函數,而在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間填寫剛才的全局結構,將消息和對應的處理函數聯系起來,并通過AFX_MSGMAP中的pBaseMap指針,將各類按繼承順序連接起來,從而提供消息流動的道路(即消息的直流,滿足標準消息流動的要求)。

下面我們舉個例子:
CMyWnd : public CWnd
{
……
DECLARE_MESSAGE_MAP()
}
BEGIN_MESSAGE_MAP(CMyWnd,CWnd)
ON_WM_CREATE()
ON_WM_PAINT()
END_MESSAGE_MAP()
被展開后,代碼如下:
CMyWnd:public CWnd
{
……
private:
static const AFX_MSGMAP_ENTRY _messageEntries[];
protected:
static AFX_DATA const AFX_MSGMAP messageMap;
virtual const AFX_MSGMAP* GetMessageMap() const;
}
const AFX_MSGMAP* CMyWnd::GetMessageMap() const
{  return &CMyWnd::messageMap;}
AFX_DATADEF const AFX_MSGMAP CMyWnd::messageMap=
{&CWnd::messageMap, &CMyWnd::_messageEntries[0]};
const AFX_MSGMAP_ENTRY CMyWnd::_messageEntries[]=
{
{WM_CREATE,0,0,0,AfxSig_is,
(AFX_PMSG)(AFX_PMSGW)(int(AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))OnCreate},
{WM_PAINT,0,0,0,AfxSig_vv,
(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(void))OnPaint},
{0,0,0,0,AfxSig_end,(AFX_PMSG)0}
};
  這樣 WM_CREATE,WM_PAINT 在消息網中流動,當流到CMyWnd類的 messageMap 結構時,發現有該消息的記錄,則調用記錄中記載的 OnCreate 和 OnPaint 函數,進行響應消息,從而完成了 Windows 消息驅動機制。

四、MFC消息的起點
  我們已經建立了一張消息流動網絡,但是消息是怎樣從產生到響應函數收到該消息,而且標準消息需要直流,命令消息還有許多拐彎(在標題二中可以看到)。不要緊張,我們只需要看看MFC是怎樣實現的。
  不管怎么說,對 Windows 系統來說都是一樣的,它都是不斷地用GetMessage(或者其它)從消息隊列中取出消息,然后用DispatchMessage將消息發送到窗口函數中去。在"窗口類的誕生"中知道,MFC將所有的窗口處理函數都注冊成DefWndProc,那是不是MFC將所有的消息都發送到DefWndProc中去了呢?很抱歉不是,而是都發送到了AfxWndProc函數去了。你可能要問為什么,這也是我想知道的,那我們就看看MFC代碼吧:
BOOL CWnd::CreateEx(……)
{
……
PreCreateWindow(cs);
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(……);
……
}
void AFXAPI AfxHookWindowCreate(CWnd *pWnd)
{
……
pThreadState->m_hHookOldCbtFilter =
::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook,NULL,::GetCurrentThreadId());
……
}
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
……
if(!afxData.bWin31)
{
_AfxStandardSubclass((HWND)wParam);
}
……
}
void AFXAPI _AfxStandardSubclass(HWND hWnd)
{
……
oldWndProc =
(WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)AfxGetAfxWndProc());
}
WNDPROC AFXAPI AfxGetAfxWndProc()
{
……
return &AfxWndProc;
}
  看了上面的代碼,不知你有沒有了然于胸的感覺"啊,原來是這樣呀!"其實MFC在PreCreateWindow注冊窗口類之后,在創建窗口之前,調用了AfxHookWindowCreate函數,該函數設置了鉤子(鉤子用SetWinowsHook或者SetWindowsHookEx設置,這樣消息有滿足設置的消息時,系統就發送給你設置的函數,這里是_AfxCbtFilterHook函數),這樣每次創建窗口的時候,該函數就將窗口函數修改成AfxWndProc。至于為什么這樣做嗎?那是為了包容新的3D控件而又同MFC2.5兼容。

五、MFC消息的流動
  消息的起點是AfxWndProc函數,所有的消息都被發送到AfxWndProc,也從AfxWndProc再次流向各自的消息響應函數的,怎么流的呢?那只有MFC知道:
LRESULT CALLBACK AfxWndProc(…….)
{
……
return AfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);
}
LRESULT AFXAPI AfxCallWndProc(……)
{
……
lResult = pWnd->WindowProc(nMsg,wParam,lParam);
……
}
LRESULT CWnd::WindowProc(……)
{
……
if(!OnWndMsg(message,wParam,lParam,&lResult))
lResult = DefWindowProc(message,wParam,lParam);
……
}
BOOL CWnd::OnWndMsg(……)//該函數原來太過龐大,被我改造了一下,只反映意思,不能執行
{
……
if(message == WM_COMMAND)
OnCommand(wParam,lParam);
if(message == WM_NOTIFY)
OnNotify(wParam,lParam,&lResult);
pMessage = GetMessageMap();
for(; pMessageMap!=NULL; pMessageMap = pMessageMap->pBaseMap)
{
if((lpEntry=AfxFindMessageEntry(pMessageMap->lpEntries,
message,0,0))!=NULL)
break;
}
(this->*(lpEntry->pnf))(……);//調用消息響應函數
}
AFX_MSGMAP_ENTRY AfxFindMessageEntry(……)
{
……
while(lpEntry->nSign!=AfxSig_end)
{
if(lpEntry->nMessage==nMsg&&lpEntry->nCode==nCode&&nID>=lpEntry->nID
&&nID<=lpEntry->nLastID)
{
return lpEntry;
}
lpEntry++;
}
……
}
  消息被發送到對應窗口的OnWndMsg后,然后根據消息的類型采取相應動作:如果是標準消息,則檢查但前類中有無處理函數(由AfxFindMessageEntry實現),若沒有,就在其父親類中找(通過pMessageMap->pBaseMap實現),這樣望上順序搜索消息網,搜索結束也找不到處理函數,那么回到WindowProc函數調用默認DefWindowProc函數;如果是命令消息或通知消息則發送到OnCommand或者OnNotify函數中去處理,來實現消息的拐彎流動:
BOOL CWnd::OnCommand(WPARAM wParam,LPARAM lParam)
{
……
return OnCmdMsg(nID,nCode,NULL,NULL);
}
BOOL CFrameWnd::OnCmdMsg(……)
{
CView* pView = GetActiveView();
if(pView!=NULL&&pView->OnCmdMsg(……))   //相當于圖1中Frame指向View的箭頭
return TRUE;
if(CWnd::OnCmdMsg(……))                    //圖1中Frame自身
return TRUE;
CWinApp *pApp = AfxGetApp();
if(pApp != NULL && pApp->OnCmdMsg(……)) //圖1中CWinApp對象
return TRUE;
return FALSE;
}
BOOL CView::OnCmdMsg(……)
{
if(CWnd::OnCmdMsg(……))                    //圖1中View本身
return TRUE;
if(m_pDocument!=NULL) m_pDocument->OnCmdMsg(……);//圖1中View到Doc箭頭
……
}
BOOL CDocument::OnCmdMsg(……)
{
if(CCmdTarget::OnCmdMsg(……))              //圖1中Doc本身
return TRUE;
if(m_pDocTemplate!=NULL&&m_pDocTemplate->OnCmdMsg(……))//圖1中Doc Template
return TRUE;
return FALSE;
}
BOOL CCmdTarget::OnCmdMsg(……)//注:CWnd沒有重載CCmdTarget的OnCmdMsg
{
……
for(pMessageMap=GetMessageMap();pMessageMap!=NULL;
pMessageMap=pMessageMap->pBaseMap)
{
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,……);
if(lpEntry!=NULL)
return DispatchCmdMsg(……lpEntry->pfn,……);
}
return FALSE;
}
  從代碼中可以看出,OnCmdMsg各自調用的順序剛好就是圖1中所要求的順序,這樣也就實現了消息的拐彎流動,最后DispatchCmdMsg 函數是調用找到的消息處理函數處理消息。至此消息從出現到找到處理函數已經完成!

posted on 2007-09-18 02:57 大龍 閱讀(2899) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   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>
            99精品热视频| 国产综合亚洲精品一区二| 亚洲精品国偷自产在线99热| 国产婷婷色综合av蜜臀av| 国产精品日韩久久久久| 国产精品成人一区二区网站软件| 国产精品久久久久久久7电影| 国产精品一区二区三区免费观看| 国内视频一区| 亚洲电影免费观看高清| 一区二区国产在线观看| 亚洲综合第一| 国产亚洲免费的视频看| 国产午夜精品美女视频明星a级| 韩国精品在线观看| 日韩视频免费观看高清完整版| 亚洲视频在线免费观看| 久久久99国产精品免费| 亚洲二区精品| 亚洲国产日韩精品| 午夜精品一区二区三区四区| 免费成人av| 国产精品久久777777毛茸茸| 樱桃国产成人精品视频| 亚洲综合精品| 亚洲国产精品成人精品| 欧美一进一出视频| 欧美国产一区二区在线观看| 国产日韩精品一区二区三区在线 | 欧美激情2020午夜免费观看| 欧美风情在线| 国产欧美一区二区三区久久人妖| 亚洲精品免费看| 久久久视频精品| 日韩写真视频在线观看| 久久嫩草精品久久久精品一| 国产精品电影网站| 亚洲精品国久久99热| 久久性色av| 亚洲一二区在线| 欧美日韩精品高清| 亚洲激情在线播放| 美女精品在线| 久久久久国产一区二区三区四区| 国产精品视频区| 亚洲一区自拍| 亚洲精品国产无天堂网2021| 免费的成人av| 亚洲高清久久| 欧美成人一区二免费视频软件| 亚久久调教视频| 国产一级一区二区| 久久高清福利视频| 欧美在线观看网址综合| 国产亚洲成精品久久| 久久精品日产第一区二区三区| 中文无字幕一区二区三区| 欧美日韩中文在线| 亚洲一二三四区| 亚洲无线视频| 国产欧美日韩视频在线观看| 久久久久久久久岛国免费| 久久经典综合| 亚洲国产婷婷综合在线精品 | 亚洲国产精品999| 美女脱光内衣内裤视频久久影院| 精品成人a区在线观看| 蜜臀av一级做a爰片久久| 久久青草欧美一区二区三区| 亚洲高清资源综合久久精品| 亚洲国产精品成人精品| 欧美日韩在线一区二区三区| 亚洲视频每日更新| 亚洲免费影视| 一区二区亚洲欧洲国产日韩| 欧美成人免费全部| 欧美激情欧美狂野欧美精品| 99国产精品视频免费观看一公开 | 亚洲国产va精品久久久不卡综合| 欧美福利电影在线观看| 欧美另类99xxxxx| 亚洲免费人成在线视频观看| 性做久久久久久久久| 亚洲国产91| 亚洲一区二区三区免费视频| 免费欧美高清视频| 老司机一区二区三区| 性欧美大战久久久久久久免费观看| 99在线精品免费视频九九视| 亚洲风情亚aⅴ在线发布| 久久激情五月丁香伊人| 亚洲福利国产精品| 91久久久在线| 国产精品久久久久久久久久久久久久 | 亚洲日韩中文字幕在线播放| 欧美午夜精品| 久久婷婷丁香| 欧美日韩国产色视频| 久久精品人人做人人爽| 欧美日韩高清不卡| 久久一区二区三区国产精品| 欧美日韩国产限制| 久久久久久一区二区三区| 欧美精品七区| 久热精品在线视频| 国产精品久久福利| 亚洲韩国青草视频| 伊人蜜桃色噜噜激情综合| 亚洲天堂av在线免费观看| 亚洲国产精品久久人人爱蜜臀| 亚洲伊人久久综合| 一区二区三区精密机械公司| 久久这里有精品15一区二区三区 | 99国产麻豆精品| 亚洲国产精品女人久久久| 性高湖久久久久久久久| 一本色道久久综合亚洲精品高清 | 久久久久国产精品一区三寸| 欧美三级日韩三级国产三级| 亚洲电影免费观看高清完整版在线| 国产日韩成人精品| 一区二区黄色| 亚洲一区二区三| 欧美日韩精品一区二区| 亚洲国产乱码最新视频| 亚洲欧洲视频在线| 美女久久一区| 免费欧美日韩| 亚洲国产成人91精品| 久热精品视频在线观看一区| 美腿丝袜亚洲色图| 伊人狠狠色丁香综合尤物| 久久爱www久久做| 久久综合网色—综合色88| 国产一区三区三区| 久久国产福利| 久久伊伊香蕉| 亚洲激情校园春色| 欧美精品一区二区高清在线观看| 欧美成人免费观看| 久久成人久久爱| 可以免费看不卡的av网站| 国产真实久久| 久久全国免费视频| 亚洲国产高清自拍| 一区二区免费在线播放| 欧美性猛交xxxx乱大交蜜桃| 亚洲色诱最新| 久久精品成人欧美大片古装| 国产曰批免费观看久久久| 久久精品视频在线观看| 欧美成人午夜激情| 中日韩美女免费视频网站在线观看| 欧美日韩在线视频一区| 亚洲欧美韩国| 欧美成年人网站| 9人人澡人人爽人人精品| 欧美性大战久久久久久久蜜臀| 亚洲欧美在线观看| 欧美二区在线| 亚洲综合色视频| 一区二区亚洲| 欧美无砖砖区免费| 欧美一区二区三区久久精品| 欧美成人a视频| 亚洲香蕉伊综合在人在线视看| 国产啪精品视频| 模特精品裸拍一区| 亚洲一区二区日本| 欧美国产欧美亚洲国产日韩mv天天看完整 | 亚洲日本欧美| 国产精品乱看| 久久香蕉国产线看观看av| 夜夜夜精品看看| 久久综合狠狠综合久久激情| 在线视频精品一区| 国内伊人久久久久久网站视频| 蜜臀a∨国产成人精品| 亚洲天堂成人在线观看| 伊人久久婷婷色综合98网| 国产精品sm| 欧美成人精品h版在线观看| 亚洲女人天堂av| 亚洲激情av在线| 久久综合伊人77777蜜臀| 亚洲午夜一区二区| 亚洲美女精品成人在线视频| 含羞草久久爱69一区| 欧美午夜一区二区福利视频| 可以免费看不卡的av网站| 亚洲欧美在线x视频| 一区二区三区精品视频| 亚洲黄色在线| 免费不卡在线视频| 欧美亚洲专区| 亚洲欧美日韩成人高清在线一区| 亚洲毛片网站| 亚洲国产精品成人va在线观看| 国产日韩精品一区二区三区在线| 欧美一区二区三区四区在线观看|