登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

江渚渔樵单片机及计算机网络

我是一只菜鸟,天高任鸟飞,学海无涯.联系方式:QQ59771230

 
 
 

日志

 
 

MFC的窗口类(如CWnd)与窗口过程  

2009-03-11 18:16:30|  分类: C++相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 Windows是基于事件机制的,任何窗口都能发送和处理消息,
每一个窗口都对应着自己的消息处理函数,即通常所说的窗口过程(WindowProc)。

窗口过程通常是在WNDCLASSEX的lpfnWndProc变量中指定的,
然后调用RegisterClassEx注册窗口类,
lpfnWndProc要求是全局的或是类的静态成员,
而MFC的窗口和类对象是一一对应的,
在类中定义的窗口过程(CWnd::WindowProc)并非类的静态成员,

那么窗口消息是怎样传给窗口对象的WindowProc函数去处理的呢?
MFC中定义了一个全局的AfxWndProc函数,
AfxWndProc是MFC中所有的窗口共用的窗口过程。
这里要注意在AfxEndDeferRegisterClass中注册窗口类时并没有把AfxWndProc赋给lpfnWndProc,
而是把DefWindowProc赋给了lpfnWndProc。

真正把AfxWndProc指定为窗口过程的是在CWnd::CreateEx函数中,
CWnd::CreateEx中先后调用了SetWindowsHookEx、CreateWindowEx
和UnhookWindowsHookEx,SetWindowsHookEx安装了一个WH_CBT类型的钩子,

在调用CreateWindowEx时(在CreateWindowEx返回之前)窗口会发送WM_CREATE、WM_NCCREATE等消息,
钩子过程CBTProc会在窗口消息WM_CREATE、WM_NCCREATE等发送前被调用,并提前得到窗口的句柄值。
钩子过程CBTProc的任务是把窗口句柄赋给窗口对象(CWnd::m_hWnd),
并调用SetWindowLong把窗口过程替换成AfxWndProc
(如是控件还要保留原窗口过程,用CallWindowProc进行默认处理)。

在这有人可能会问,为什么不在AfxEndDeferRegisterClass中直接指定AfxWndProc呢?
当然是有原因的:
其一是控件的窗口过程必须用SetWindowLong来替换,
其二是消息WM_CREATE,WM_NCCREATE等是在CreateWindowEx返回前发送的,
CWnd::WindowProc在处理这些消息时CWnd::m_hWnd必须是已经被初始化的,
这个就是由前面的CBTProc完成的。

 
好现在我们只要关注AfxWndProc了。
AfxWndProc是如何把消息分配给各个窗口对象的窗口过程的呢?
在MFC中有一个全局的映射表(还没到消息映射,呵呵),
这个表是窗口句柄到窗口对象的映射(即通过窗口句柄就能找到窗口对象的地址),
找到了窗口对象就可以把消息处理的任务交给CWnd::WindowProc了(调用pWnd->WindowProc)。

以上红字部分要考虑一下.

下面就是消息映射了
其实这就简单了,因为这时只需关注CWnd::WindowProc和消息处理函数(如onCreate)了。
在MFC中定义了几个宏:DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、END_MESSAGE_MAP等,
其实把这几个宏换回来就很好理解了。

 

 

对于传递函做个解释如下:

AfxWndProc()     
该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc

AfxCallWndProc() 
该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,
然后调用WindowProc()函数

WindowProc()     
该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数

OnWndMsg()       
该函数的功能首先按字节对消息进行排序,
对于WM_COMMAND消息,调用OnCommand()消息响应函数,
对于WM_NOTIFY消息调用OnNotify()消息响应函数。
任何被遗漏的消息将是一个窗口消息。
OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。
如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,
由它将消息发送给DefWindowProc()函数

OnCommand()      
该函数查看这是不是一个控件通知
(lParam参数不为NULL,如果lParam参数为空的话,说明该消息不是控件通知),
如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;
如果他不是一个控件通知(或者如果控件拒绝映射的消息)OnCommand()就会调用OnCmdMsg()函数

OnNotify()也试图将消息映射到制造通知的控件;
如果映射不成功,OnNotify()就调用相同的OnCmdMsg()函数

OnCmdMsg()       
根据接收消息的类,
OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。
例如:如果拥有该窗口的类是一个框架类,
则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数

  评论这张
 
阅读(674)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018