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

            隨筆分類

            收藏夾

            大家的聲音

            積分與排名

            最新評論

            閱讀排行榜

            評論排行榜

            久久影院综合精品| 国产伊人久久| 一本综合久久国产二区| 国产A级毛片久久久精品毛片| 久久WWW免费人成一看片| 久久人人爽人人爽人人片AV麻豆| 久久天堂电影网| 99久久精品免费看国产| 91精品国产综合久久香蕉 | 中文字幕久久精品无码| 亚洲国产精品综合久久网络| 久久久精品人妻无码专区不卡| 国产精品免费久久久久电影网| 久久噜噜电影你懂的| 国产精品永久久久久久久久久 | 99久久久精品免费观看国产| 亚洲AV无码久久精品蜜桃| 色综合久久综合中文综合网| 97久久久久人妻精品专区 | 中文字幕热久久久久久久| 精品综合久久久久久98| 久久精品亚洲日本波多野结衣 | 久久免费线看线看| 久久久精品日本一区二区三区 | 99久久国产热无码精品免费| 99久久精品免费看国产一区二区三区| 亚洲国产精品婷婷久久| 精品水蜜桃久久久久久久| 三级三级久久三级久久| 2021少妇久久久久久久久久| 久久一区二区三区免费| 国产精品久久久久久吹潮| 美女写真久久影院| 思思久久99热只有频精品66| 久久99精品国产99久久| 日本五月天婷久久网站| 91精品国产91热久久久久福利| 日本WV一本一道久久香蕉| 一本一道久久精品综合| 久久久久亚洲av无码专区导航 | 青青草原综合久久|