MFC消息机制 2

时间:2022-07-01 05:06:53

接上篇

 

1、 消息的处理流程

好了,有了前面12小节的基础,我们接下来来看消息的处理流程:

以下描述消息从AfxWndProc起点开始的处理流程:

1)        AfxWndProc(HWND hWndUnit nMsg….)

说明,这里的hWnd指定了到底从哪个窗口开始接收并处理消息;

AfxWndProc中,调用了AfxCallWndProc函数,

pWnd已经不是句柄了,而是由句柄得到的一个具体的CWnd指针指向的窗口类CWnd* pWnd=CWnd::FormatHandlePermant(hWnd)

2)        AfxCallWndProc(CWnd *pWndUnit nMsg…..)

说明:,在AfxCallWndProc函数中,调用了pWnd->WindowProc (nMsg…….)

其实至此,消息走到了具体的MFC管理范围之内,以后消息就交给MFC类来处理了!

这里需要注意的是,其实pWnd->WindowProc,并不一定调用的就是CWndWindowProc函数,因为WindowProc是个虚函数,实际中,要看从一开始,即AfxWndProc开始,hWnd指的是什么窗口界面,当然这个窗口类肯定继承自CWnd,所以才可以用CWnd基类指针嘛!实际中,CcontrolBarCOleControlColePropertyPageCDialog、等等都重载了WindowProc,而且CFrameWndCview都继承自CWnd这里其实隐含了一个道理,即从AfxWndProc接收的消息,入口都是[微软用户1] CWnd的继承类,可以是CDialogCView(以及继承类)CframeWnd等等。

问题,AfxWndProc的起点可以是非CWnd子类吗?比如Cdocument?能否向一个Cdocument SendMessage? 好了先不说这个,继续往下走。。。。

3)        CWnd::WindowProc()

在这个函数中,又调用了

OnWndMsg()

    以及OnWndMsg处理失败后的DefWindowProc

    先不管DefWindowProc,先来看看OnWndMsg(),当然具体调用哪个类的OnWndMsg,要看当前的CWnd子类是什么,是个CviewCframeWndCdialog

   CWndOnWndMsg函数是个虚函数,许多子类都重载了OnWndMsg(),在“深入浅出MFC”中,只分析了CWndOnWndMsg[微软用户2] 

    好了继续往下走,看看CWndOnWndMsg是怎么处理消息的:

l         对于WM_Command消息,调用 OnCommand

l         对于WM_Notify消息,调用OnNotify

l         对于除此之外的一般消息,就依据消息映射表上溯了

 

接下来我们分析对WM_Command消息的处理

4)        OnCommand

OnCommandCWnd的一个虚函数[微软用户3] ,实际中要看This指针指得是CWnd的哪个派生类。这些类都重载了OnCommand,有CWndCframeWndCMDIFrameWndCspliteFrameWnd等等。

实际中,要看消息是从哪个类中进来的,比如消息是从CframeWnd进来的,那么就调用CframeWndOnCommand

CframeWnd::OnCommand[微软用户4] (…)

{ ……

  CWnd::OnCommand()

}

 

CWnd::OnCommand()

{…..

   OnCmdMsg()

}

 

注意,这时候消息是从CframeWnd进来的,那么实际调用的就是CframeWnd::OnCmdMsg()

实际中,许多类都重写了OnCmdMsg函数,有如下:

CcmdTarget::Cobject[微软用户5] 

CframeWnd::CWnd

CMDIFrameWnd::CframeWnd

Cview::CWnd

Cdialog::CWnd

那么,消息从哪里进来,就调用谁的OnCmdMsg,比如从Cview进来,自然调用Cview->OnCmdMsg

 

下面来看看CframeWnd::OnCmdMsg()

5)        CframeWnd::OnCmdMsg()

{

  (注意,这里出现了多路分支)

1  Cview::pView->OnCmdMsg;

  2  CWnd->OnCmdMsg

  3  pApp->OnCmdMsg

 

}

6)        先说1

Cview::OnCmdMsg

{

1、  CWnd::OnCmdMsg   A

2、  m_pDocument->OnCmdMsg

}

1中,由于CWnd没有重写OnCmdMsg,所以实际调用的是CcmdTarget::OnCmdMsg,那么CcmdTarget::OnCmdMsg做什么工作呢?它的工作就是对比消息映射表,看看能不能拦截该消息。

(这里千万不要犯迷糊,不要被CcmdTarget迷惑,因为是从A进来的,那么其实对比的是1 pView的消息映射表)

如果Cview处理不了该消息,那就只好由2处的m_pDocument进行处理了,即

View然后文档

7)        如果1处理不了,则交给2处理

按照“深入浅出MFC”的说法, 2实际上是判断当前框架的消息映射表,能不能处理当前消息,即沿着CMyFrameWnd->CFrameWnd->CWnd的路径来寻找消息映射匹配,刚开始我还不明白,在2处,明明是CWnd->OnCmdMsg,怎么会先从CmyFrameWnd开始呢?往前想想,我们分析的这条消息是从哪里进来的?CMyFrameWndthis指针指向CMyFrameWnd,当然要从CmyFrameWnd开始了,CmyFrameWnd只是借用了CcmdTarget的代码而已

8)        好,如果12、都处理不了,最后只能寄希望于3了,即pApp->OnCmdMsg

如果3也处理不了,那只好go back。。go back。。回到3)的DefWindowProc

 

好了 我们完整分析了消息从CmyFrameWnd进来的处理流程,这个处理是参考深入浅出MFC”中的,书中有一个图9-6,从大局上描述了这个流程。MFC消息处理确实很复杂,需要很多遍才稍微感觉有点儿明白了的。其实,这里面最关键的就是多态!多态!一定不要被代码里面写的类名迷糊,要时刻想想当前代码段儿的This指针指得对象是谁?消息是从哪里进来的?

 

还有几个问题不知道对不对,或者不理解,如下:

1、“深入浅出MFC”只列举了一个命令消息,从CframeWnd进来的处理流程,那么消息从其它地方进来的流程是什么呢?比如从CviewCdialog进来呢?

估计只是从CframeWnd进来的消息处理流程的一段儿,所以候捷只列举了一个,自己可以跟踪验证一下[微软用户6] Cview传入的消息,能不能被CframeWnd或者CmyApp处理呢?

2、“深入浅出MFC”只列举了命令消息(WM_Command)的处理流程,那么WM_Notify和其它一般消息的处理流程是什么呢?


 [微软用户1]这里,“深入浅出MFC”缺少一个总结,我的理解不知道对不对

 [微软用户2]这里“深入浅出MFC”只分析了CWndOnWndMsg,其实CVew、等其它CWnd的子类都重载了OnWndMsg,它们有什么不同,自己需要分析一下

 [微软用户3]CcmdTarget的虚函数,还是CWnd的虚函数?

 [微软用户4]其它几个重载了OnCommand的函数,是否也都是调用了CWnd::OnCommand呢?

 [微软用户5]看来,OnCmdMsgCcmdTarget的虚函数

 [微软用户6]验证消息从CviewCdialog进来的流程