现在的位置: 首页 > 综合 > 正文

MFC消息映射及路由

2013年11月14日 ⁄ 综合 ⁄ 共 1635字 ⁄ 字号 评论关闭
介绍的顺序按照从浅入深来

认识1

在mfc中消息路由机制就是指将发送给窗口的消息发给该窗口对应的窗口类所提供的相应的成员函数。这句话的关键字是 窗口对应的窗口类  窗口类对应的成员函数。首先说 窗口对应的窗口类,mfc使用全局函数AfxWndProc取代所有窗口的窗口过程函数,在这个函数里面通过类似字典的形式采用窗口句柄作为索引查找到对应的窗口类对象。

	// all other messages route through message map
	CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);

得到窗口类后,现在就是要找消息对应的成员函数了,这个功能是通过下面的几个东西来支持的:

BEGIN_MESSAGE_MAP(theClass, baseClass)
END_MESSAGE_MAP()
DECLARE_MESSAGE_MAP()

上面是用到的3个宏,前2个其实用来支持一个东西,用来生成一个类的静态的结构体,该结构体描述了消息的id,处理函数的原型等信息。第3个宏很关键,它采用C++的虚函数,通过该机制,可以得到当前类的描述消息和其对应处理成员函数的表,让消息的路由从子类沿父类路由(大部分是这样,但是也有消息不路由给父类的情况)。

通过上面的介绍我们可以有个大概的概念了:首先所有窗口的消息统一由AfxWndProc来处理,该函数根据窗口句柄查表(后面会介绍这个表的细节)得到对应的窗口类对象(注意这个是用指针CWnd表示的,但是由于虚函数机制,我们会调用正确的子类函数),该窗口类对象会获得其消息查找表,查找对应的处理函数进行调用。

认识2

看看消息的路由规则吧。

首先,我们知道所有窗口的窗口函数都是AfxWndProc(可能是一个Base什么的函数,但是最后也会调用AfxWndProc),这个函数首先通过一个表得到对应窗口的窗口类,然后调用窗口类的WindowProc函数(该函数是个虚函数),其原型为

virtual LRESULT WindowProc(
   UINT message,
   WPARAM wParam,
   LPARAM lParam 
);

如此,可以知道我们可以重载该函数来处理原生态的消息,但是最好在最后还是调用下基类的这个函数。

这个函数会调用OnWndMsg来处理几乎所有的消息,其原型为:

virtual BOOL OnWndMsg(
   UINT message,
   WPARAM wParam,
   LPARAM lParam,
   LRESULT* pResult 
);

看到没,这个函数又提供了我们处理原生态消息的机会,如果你想要直接搞定windows消息,重写这个函数也是阔以的。

在这个函数中,分3种情况对windows消息进行了处理:

1.WM_COMMAND。调用虚函数OnCommand处理。如果处理了就直接返回。

2.WM_NOTIFY。调用虚函数OnNotify处理。如果处理了就直接返回。

3.WM_ACTIVATE。用函数_AfxHandleActivate.返回后去到第5类进行第二次处理。
4.WM_SETCURSOR。_AfxHandleSetCursor,处理了直接返回。

5.其它所有函数。首先在一个消息缓冲池中进行查找,如果能找到处理函数,就调用。找不到就根据消息映射表查找进行处理。

好了,大致的情况就是这样了,下面看看很难搞的WM_COMMAND消息。这个消息的路由还是比较复杂的。

OnCommand会调用OnCmdMsg,路由大部分是这个函数干的事情。

首先,调用当前活动窗口的OnCmdMsg,意思就是活动窗口你先处理吧。返回值表明了消息是不是被处理了。

2了,如果OnCmdMsg不处理,就给文档类处理。

3了,文档类也不要的话,就自己来了,也就是CCmdTarget::OnCmdMsg,这里框架可能会自己处理该消息。

4了,还没人要就给App::OnCmdMsg,这个函数也不要就给默认的处理函数。

好了,一个消息的处理就完成了。

有些地方可能会有问题,欢迎大家指正吧。

抱歉!评论已关闭.