2010.7.5
1、文章阅读:
http://blog.csdn.net/chief1985/archive/2007/11/23/1899468.aspx
http://www.docin.com/p-4218188.html#
2、MFC消息机制
Windows应用程序的消息来源有一下四种:
1)输入消息:包括键盘和鼠标的输入。这一类消息首先放在系统消息队列中,然后由Windows将它们送入应用程序消息队列中,由应用程序来处
理消息。(常用)
2)控制消息:用来与Windows的控制对象,如列表框、按钮、检查框等进行双向通信。当用户在列表框中改动当前选择或改变了检查框的状态时
发出此类消息。这类消息一般不经过应用程序消息队列,而是直接发送到控制对象上去。(常用)
3)系统消息:对程序化的事件或系统时钟中断作出反应。一些系统消息,象DDE消息(动态数据交换消息)要通过Windows的系统消息队列,而
有的则不通过系统消息队列而直接送入应用程序的消息队列,如创建窗口消息。
4)用户消息:这是程序员自己定义并在应用程序中主动发出的,一般由应用程序的某一部分内部处理。
下面看一个标准的输入消息的处理步骤:
一个输入消息从产生,到被应用程序窗口接受、处理主要分两大步:
一、Windows系统处理阶段;
1、Windows接受到后,放到系统消息队列;
2、由系统分发到应用程序消息队列;
二、Windows系统将消息交给应用程序,程序处理阶段
1、通过消息循环,应用程序从消息队列中检索消息,再把它分派给适当的窗口。(也有这种说法,消息是停留在消息队列中,等待被所隶属的窗口抓取)
2、每个窗口都有一个窗口过程(又叫窗口函数WindowProc),以接收Windows 传递给窗口的消息,窗口过程的任务就是获取消息并且响应它。(但实际上,MFC中所有窗口公用一个窗口过程)。(待确定?为什么这么做?原因是什么?MFC版本不同,此处也不同)
每个窗口会有一个称为窗口过程的回调函数(WndProc),它带有四个参数,分别为:窗口句柄(Window Handle),消息ID(Message ID),和两个消息参数 (wParam, lParam), 当窗口收到消息时系统就会调用此窗口过程来处理消息。(所以叫回调函数)
注意,以上是在Windows中,并不是在MFC中。
消息队列(Message Queues)
Windows中有两种类型的消息队列
1) 系统消息队列(System Message Queue)
这是一个系统唯一的Queue,设备驱动(mouse, keyboard)会把操作输入转化成消息存在系统队列中,然后系统会把此消息放到目标窗口所在的线程的消息队列(thread-specific message queue)中等待处理
2) 线程消息队列(Thread-specific Message Queue)
每一个GUI线程都会维护这样一个线程消息队列。(这个队列只有在线程调用GDI函数时才会创建,默认不创建)。然后线程消息队列中的消息会被送到相应的窗口过程(WndProc)处理.
注意: 线程消息队列中WM_PAINT,WM_TIMER只有在Queue中没有其他消息的时候才会被处理,WM_PAINT消息还会被合并以提高效率。其他所有消息以先进先出(FIFO)的方式被处理。
根据消息经过的位置,分为:
队列消息(Queued Messages)和非队列消息(Non-Queued Messages)
1)队列消息(Queued Messages)
消息会先保存在消息队列中,消息循环会从此队列中取消息并分发到各窗口处理,如鼠标,键盘消息。
2) 非队列消息(NonQueued Messages)
消息会绕过系统消息队列和线程消息队列直接发送到窗口过程被处理,如:WM_ACTIVATE,WM_SETFOCUS,WM_SETCURSOR, WM_WINDOWPOSCHANGED
注意: postMessage发送的消息是队列消息,它会把消息Post到消息队列中; SendMessage发送的消息是非队列消息, 被直接送到窗口过程处理
MFC是如何处理的:
1、MFC的窗口类都通过钩子函数_AfxCbtFilterHook截获消息,并且在钩子函数_AfxCbtFilterHook中把窗口过程设定为AfxWndProc。
2、MFC应用程序中的消息泵在CWinApp的成员函数Run()中。应用程序开始运行时,Run()就被调用,Run()把时间分割成两部分。一部分用来执行后台处理,如取消临时CWnd对象;另一部分用来检查消息队列。当一个新的消息进来时,Run()抽取它—即用GetMessage( )从队列中取出该消息,运行PreTranslateMessage( )和::TranslateMessage( )两个消息翻译函数,然后用DispatchMessage( )函数调用该消息预期的目标窗口进程。
(DispatchMessage分发到什么地方呢?所有窗口公用一个窗口过程?怎么理解呢?)