• <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>

            牧光小院

            被約束的日日夜夜,停不下來的時間。

            MFC漫談(五)——消息的路由(2)

            繼續上一個主題



            直線上溯的消息

            上次說到消息被轉發到了AfxWndProc,繼續。

            LRESULT?CALLBACK
            AfxWndProc(HWND?hWnd,?UINT?nMsg,?WPARAM?wParam,?LPARAM?lParam)?
            {
            ????
            //?…

            ????
            //?all?other?messages?route?through?message?map
            ????CWnd*?pWnd?=?CWnd::FromHandlePermanent(hWnd);
            ????
            //?…
            ????return?AfxCallWndProc(pWnd,?hWnd,?nMsg,?wParam,?lParam);
            }


            LRESULT?AFXAPI?AfxCallWndProc(CWnd
            *?pWnd,?HWND?hWnd,?UINT?nMsg,
            ????????????????????????WPARAM?wParam?
            =?0,?LPARAM?lParam?=?0)?{
            ????
            //?…
            ????
            //?Catch?exceptions?thrown?outside?the?scope?of?a?callback
            ????
            //?in?debug?builds?and?warn?the?user.
            ????LRESULT?lResult;
            ????
            //?…
            ????
            //?delegate?to?object's?WindowProc
            ????lResult?=?pWnd->WindowProc(nMsg,?wParam,?lParam);
            ????
            //?…
            ????return?lResult;
            }

            最后,消息被傳到了WindowProc中,這是一個CWnd類中的虛函數,而MFC則通過虛函數機制把消息的處理直接轉發到相應窗口的窗口過程(例如CFrameWnd),這里,我們來看CWnd::WndProc

            LRESULT?CWnd::WindowProc(UINT?message,?WPARAM?wParam,?LPARAM?lParam)? {
            ????
            // ?OnWndMsg?does?most?of?the?work,?except?for?DefWindowProc?call
            ????LRESULT?lResult? = ? 0 ;
            ????
            if ?( ! OnWndMsg(message,?wParam,?lParam,? & lResult))
            ????lResult?
            = ?DefWindowProc(message,?wParam,?lParam);
            ????
            return ?lResult;
            }

            首先利用OnWndMsg處理消息,如果OnWndMsg沒能處理消息,調用DefWindowProc。先來看OnWndMsg,這是一個CWnd類的虛函數,這個函數的邏輯很簡單,如果消息是WM_COMMAND或WM_NOTIFY,則把消息分別交給OnCommand和OnNotify處理,否則首先在MFC內建的消息緩存中查找消息,如果命中但沒有相應的處理函數,則返回FALSE(這樣的話會交由CWnd::DefWindowProc處理),如果命中,則進一步判斷是用戶自己注冊的消息還是標準Windows消息,如果是前者,就跳到標LDispatchRegistered處理,調用相應的消息處理函數,否則就跳到LDispatch處理,調用正確的消息處理函數。

            如果消息不在緩存中,那么就沿著某個類的繼承路線,由AfxFindMessageEntry在每一個類的消息映射表中查找,如果找到匹配項,同樣按照是否是用戶注冊的消息的邏輯對消息進行處理,如果始終沒有找到匹配項,則返回FALSE,交由CWnd::DefWindowProc處理。

            BOOL?CWnd::OnWndMsg(UINT?message,?WPARAM?wParam,?LPARAM?lParam,?LRESULT * ?pResult)
            {
            ????
            //
            ?
            ????
            // ?special?case?for?commands

            ???? if ?(message? == ?WM_COMMAND)
            ????
            {
            ????????
            if ?(OnCommand(wParam,?lParam))?? // ?對WM_COMMAND交給OnCommand處理

            ???????? {
            ????????????lResult?
            = ? 1
            ;
            ????????????
            goto
            ?LReturnTrue;
            ????????}

            ????????
            return ?FALSE;
            ????}


            ????
            // ?special?case?for?notifies
            ???? if ?(message? == ?WM_NOTIFY)
            ????
            {
            ????????NMHDR
            * ?pNMHDR? = ?(NMHDR *
            )lParam;
            ????????
            if ?(pNMHDR -> hwndFrom? != ?NULL? && ?OnNotify(wParam,?lParam,? &
            lResult))
            ????????????
            goto
            ?LReturnTrue;
            ????????
            return
            ?FALSE;
            ????}

            ????
            // ?…?…
            ???? const ?AFX_MSGMAP * ?pMessageMap;?pMessageMap? = ?GetMessageMap();? // ?獲取類的消息映射表
            ????
            // ?

            ????AFX_MSG_CACHE * ?pMsgCache;?
            ????pMsgCache?
            = ? &
            _afxMsgCache[iHash];
            ????
            const ?AFX_MSGMAP_ENTRY *
            ?lpEntry;
            ????
            // ?判斷消息是否在緩存中

            ???? if ?(message? == ?pMsgCache -> nMsg? && ?pMessageMap? == ?pMsgCache -> pMessageMap)? {
            ????????
            // ?cache?hit

            ????????lpEntry? = ?pMsgCache -> lpEntry;
            ????????AfxUnlockGlobals(CRIT_WINMSGCACHE);
            ????????
            if ?(lpEntry? == ?NULL)? // ?在緩存中,但是沒有相應的表項,返回FALSE

            ???????? return ?FALSE;

            ????????
            // ?cache?hit,?and?it?needs?to?be?handled

            ???????? if ?(message? < ? 0xC000 )? // ?否則,按照是否是用戶自定義的消息,?跳轉到相應的位置
            ???????????? goto ?LDispatch;? // ?標準Windows消息
            ???????? else
            ????????????
            goto ?LDispatchRegistered;? // ?用戶自定義消息
            ????}

            ????
            else ? // ?如果消息不在緩存中,就只好挨家挨戶檢查一番
            ???? {
            ????????
            // ?not?in?cache,?look?for?it

            ????????pMsgCache -> nMsg? = ?message;
            ????????pMsgCache
            -> pMessageMap? =
            ?pMessageMap;
            ????????
            // ?下面這個for循環從派生類到基類檢查每一個類的消息映射表

            ???????? for ?( /* ?pMessageMap?already?init'ed? */ ;?pMessageMap? != ?NULL;
            ????????????pMessageMap?
            = ?pMessageMap -> pBaseMap)??
            {
            ????????????
            if ?(message? < ? 0xC000 )? // ?如果消息是Windows標準消息

            ???????????? {
            ????????????????
            // ?constant?window?message

            ???????????????? if ?((lpEntry? = ?AfxFindMessageEntry(pMessageMap -> lpEntries,
            ????????????????message,?
            0 ,? 0 ))? != ?NULL)?
            {
            ????????????????????pMsgCache
            -> lpEntry? =
            ?lpEntry;
            ????????????????????AfxUnlockGlobals(CRIT_WINMSGCACHE);
            ????????????????????
            goto ?LDispatch;? // ?如果找到對應項,就轉去處理

            ????????????????}

            ????????????}

            ????????????
            else ? // ?如果是用戶自定義消息
            ???????????? {
            ????????????????
            // ?registered?windows?message

            ????????????????lpEntry? = ?pMessageMap -> lpEntries;
            ????????????????
            while ?((lpEntry? = ?AfxFindMessageEntry(lpEntry,? 0xC000 ,? 0 ,? 0 ))? !=
            ?NULL)
            ????????????????
            {
            ????????????????????UINT
            * ?pnID? = ?(UINT * )(lpEntry ->
            nSig);
            ????????????????????ASSERT(
            * pnID? >= ? 0xC000 ? || ? * pnID? == ? 0
            );
            ????????????????????
            // ?must?be?successfully?registered

            ???????????????????? if ?( * pnID? == ?message)
            ????????????????????
            {
            ????????????????????????pMsgCache
            -> lpEntry? =
            ?lpEntry;
            ????????????????????????AfxUnlockGlobals(CRIT_WINMSGCACHE);
            ????????????????????????
            goto ?LDispatchRegistered;? // ?如果找到就轉去處理

            ????????????????????}

            ????????????????????????lpEntry
            ++ ;?????? // ?keep?looking?past?this?one
            ????????????????}

            ????????????}

            ????????}

            ????????
            // ?即不在緩存中,所有的類也都對此消息置之不理,那么就返回FALSE,交由CWnd::DefWndProc
            ????????
            // ?處理

            ????????pMsgCache -> lpEntry? = ?NULL;
            ????????AfxUnlockGlobals(CRIT_WINMSGCACHE);
            ????????
            return
            ?FALSE;
            ????}

            ????
            // ?下面是對Windows標準消息和用戶自定義消息的處理
            LDispatch:
            ????ASSERT(message?
            < ? 0xC000
            );

            ????mmf.pfn?
            = ?lpEntry ->
            pfn;

            ????
            switch ?(lpEntry ->
            nSig)
            ????
            {
            ????
            default
            :
            ????????ASSERT(FALSE);
            ????????
            break
            ;

            ????
            case
            ?AfxSig_b_D_v:
            ????????lResult?
            = ?( this ->* mmf.pfn_b_D)(CDC::FromHandle(reinterpret_cast < HDC >
            (wParam)));
            ????????
            break
            ;

            ????
            case
            ?AfxSig_b_b_v:
            ????????lResult?
            = ?( this ->* mmf.pfn_b_b)(static_cast < BOOL >
            (wParam));
            ????????
            break
            ;

            ????
            case
            ?AfxSig_b_u_v:
            ????????lResult?
            = ?( this ->* mmf.pfn_b_u)(static_cast < UINT >
            (wParam));
            ????????
            break
            ;

            ????
            case
            ?AfxSig_b_h_v:
            ????????lResult?
            = ?( this ->* mmf.pfn_b_h)(reinterpret_cast < HANDLE >
            (wParam));
            ????????
            break
            ;
            ????????
            // ?…?…

            ????}

            ?
            goto ?LReturnTrue;
            LDispatchRegistered:????
            // ?for?registered?windows?messages

            ????ASSERT(message? >= ? 0xC000 );
            ????ASSERT(
            sizeof (mmf)? == ? sizeof
            (mmf.pfn));
            ????mmf.pfn?
            = ?lpEntry ->
            pfn;
            ????lResult?
            = ?( this ->*
            mmf.pfn_l_w_l)(wParam,?lParam);

            LReturnTrue:
            ????
            if ?(pResult? !=
            ?NULL)
            ?????
            * pResult? =
            ?lResult;
            ????
            return
            ?TRUE;
            }

            寫到這里,對于直線上溯的消息的處理過程,應該是很清楚了,概括一下,就是先準備好兩個處理過程,一個用來處理標準Windows消息,一個用來處理用戶自定義消息,之后,根據消息是不是在緩存中,進行不同的查找,如果找到,根據消息的類型轉到不同的處理過程中去,如果處理過了,就返回TRUE,否則返回FALSE,交由CWnd::DefWindowProc處理。到此,關于直線上溯消息的處理就結束了,很簡單,無非就是從派生類到基類的一個比較操作,真正復雜些的是MFC對于WM_COMMAND消息的處理,我們后面再說了。

            posted on 2006-05-19 09:08 nacci 閱讀(4654) 評論(3)  編輯 收藏 引用 所屬分類: C++漫談

            評論

            # re: MFC漫談(五)——消息的路由(2) 2006-09-05 11:21 lll

            11  回復  更多評論   

            # re: MFC漫談(五)——消息的路由(2) 2007-10-11 16:05 seamonst

            全明了。非常感謝!
            期待對OnCommand的進一步分析。  回復  更多評論   

            # re: MFC漫談(五)——消息的路由(2)[未登錄] 2008-07-08 15:03 sky

            very good! thanks! Up!  回復  更多評論   

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導航

            統計

            常用鏈接

            留言簿(2)

            隨筆分類

            收藏夾

            大家的聲音

            積分與排名

            最新評論

            閱讀排行榜

            評論排行榜

            久久亚洲精品无码AV红樱桃| 欧美色综合久久久久久| 久久久噜噜噜久久熟女AA片| 日韩av无码久久精品免费| 国产精品岛国久久久久| 久久久久国产日韩精品网站| 综合网日日天干夜夜久久| 久久夜色精品国产亚洲| 久久经典免费视频| 99久久综合狠狠综合久久止| 久久综合五月丁香久久激情| 国产成人精品久久一区二区三区| 久久无码国产| 国产精品无码久久久久| 精品国产一区二区三区久久久狼 | 国产精品热久久无码av| 亚洲精品高清国产一线久久| 国产69精品久久久久9999| AAA级久久久精品无码片| 亚洲综合伊人久久大杳蕉| 国产精品青草久久久久福利99| 久久99精品国产麻豆 | 久久精品天天中文字幕人妻| 免费一级做a爰片久久毛片潮| 久久精品成人免费网站| 久久这里只有精品18| 无码日韩人妻精品久久蜜桃 | 18禁黄久久久AAA片| 国产精品久久久久乳精品爆 | 情人伊人久久综合亚洲| 色欲综合久久躁天天躁蜜桃| 久久婷婷五月综合国产尤物app| 久久久久国产一区二区| 国产精品99久久久久久www| 精品久久久久久无码专区| 国产精品美女久久久久| AV色综合久久天堂AV色综合在| 色狠狠久久综合网| 亚洲国产成人久久综合区| 久久精品国产2020| 国产午夜电影久久|