日期:2014-05-17  浏览次数:20829 次

Windows 消息机制详解

Windows 消息机制详解

zz from
???? http://www.360doc.com/content/10/0531/23/1131125_30579505.shtml

总的来说:
MSG包括:
窗口句柄,指示MSG发送的目的窗口
消息标识
lPARAM、wParam
发送时间
发送时的鼠标位置
?
关于消息队列:
Windows系统有一个系统消息队列
每个线程都有一个自己的消 息队列(由于发送消息MSG需 要提供一个窗口HWnd,而基 本有窗口的线程,都是UI线 程),因此基本上如果线程使用了GDI函数,则windows给该线程分配一个线程消息队列,这个消息队列负责该线程的所有窗口的消息。
?
所有的窗口都有自己的句柄(HWND),消息被发送时,这个句柄就已经被指定了。所以 当子窗口收到一个消息时,其父窗口不会也收到这个消息,除非子窗口手 动的转发。
?
消息分为:
实际上MSDN把消息分为队列型(Queued Message)和非队列型(Non-queued Message),这只是不同的路由方式, 但最终都会由消息处理函数来处理。
队 列型消息包括硬件的输入(WM_KEY*等)、WM_TIMER消 息、WM_PAINT消息等;非队列型的一些例子有WM_SETFOCUS, WM_ACTIVE, WM_SETCURSOR等,它们被直接发送给处理函数。
其实,按照MSDN的说法和消息的路由过程可以理 解为,Posted Message Queue里的消息是真正的队列型消 息,而通过SendMessage()发送到消息,即使它进入了Sent Message Queue,由于SendMessage要求的同步处理,这些消息也 应该算非队列型消息。也许,Windows系统会特殊处理,使消息强行绕 过队列。
?
?

=====================

一节详细描述消息和消息队列以及如何在 你程序中使用他们。
关于消息和消息 队列
与传统的应用程序不 同,Microsoft Windows应用程序并不显式地用一个函数的调用(如c运行库)来获取输入,而是,等待windows系统把输入传给它们。
windows系统把应用程序 的所有输入传给应用程序的窗口,每个窗口都有一个称之为窗口过程的函数.当窗口有输入时windows系统要调用它,窗口过程处理输入并把控制返回 windows系统。有关窗口过程,参见 “窗口过程”。 这一章讲述消息及消息队列,并说明在应用程序中如何使用它们。
消息
windows系统以消息的形式把输入传给窗口过程,消息是由windows系 统或应用程序产生的.windows系统对每一个输入事件都要产生消息,例如,用户按键盘、移动鼠标或单击一个滚动条控制框。windows系统为了响应 应用程序给系统带来的变化也会产生消息,比如应用程序改变了系统字体资源池或是改变了一个窗门的大小。应用程序可通过产生消息指导它自己的窗口来完成某个 任务,或是与其它应用程序的窗口进行通信。
windows 系统把消息发送给窗口过程.窗口过程有四个参数:窗口句柄、消息标识以及两个叫做消息参数的32位值。窗口句柄决定消息将发送到哪—个窗 口,windows系统则用它来确定向哪一个窗口过程发送消息。
消息标识是一个命名的常量,由它来标明消息的目的。如果窗口过程接收到一条消息,它就通过消息标识来决定如何处理这条 消息。例如,消息标识WM_PAINT 通知窗口过程,窗口的客户区被改变了,需要重画。
消息参数指定窗口过程在处理消息时所用的数据或数据的位 置,消息的意图及数值取决了消息本身。消息参数可以是一个整数、紧缩的位标志、一个含有附加数据结构的指针等等。如果消息不使用消息参数,一般就都设置成NULL 、 窗口过程必须检查消息标识以确定如何解释消息参数。
消息路由
windows系统用两种方式向窗口过程发送消息:把消息投递到一个先进先出的消息队列中,它是一个系统定义的内存块用于临时存储消息;或是把消 息直接发给窗口过程。
投递到 消息队列中的消息叫排队消息,它们主要是用户通过鼠标或键盘的输入结果.如WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR 消息。其它的排队消息包括定时器、绘制和退出消息:WM_TIMER, WM_PAINT, and WM_QUIT 。所有直接发送到窗口过程的其它消息称之为非排队消息。
排队消息
windows系统在同一时间可显示多个窗口,要发送鼠标和键盘输入到相应 的窗口,windows系统要用到消息队列,它要管理一个系统消息队列和任意数目线程消息队列,每一个队列对应于一个线程。
不管什么时候,只要用户移动鼠标或是敲键盘.鼠标或键盘的 设备驱动器都要把输入转换成消息,并把它们放到系统消息队列中去。windows从系统队列中每次移走一条消息,确定目的窗口,再把它们投递到创建目的窗 口的线程的消息队列中,线程消息队列接收所有由该线程创建的窗口的鼠标和键盘消息。线程从它的队列中移走消息并指导windows系统将它们发送到相应的 窗口过程进行处理。有关线程,参见 “进程和线程”。
WM_PAINT 消息有点特别,windows系统总是把这条消息放在消息队列的最后,这样 可保证窗口按先进先出次序接收它的输入消息,WM_PAINT 消息被保持在队列中,只有在队列中没有其它消息时才发送 到窗口过程。同一个窗口的多个WM_PAINT 消息被合并成一个WM_PAINT 消 息,把客户区所有无效部分合并成一个区域.合并WM_PAINT 消息节约了窗口必须重画客户区内容的时间。
系统向线程消息队列投递消息是通过填充 一个MSG 结构,再把它复制到消息队列中,MSG 结构中的信息包括接收消息的窗口 句柄、消息标识、两个消息参数、消息时间以及鼠标的位置,线程可把消息投递到它自己的消息队列中或是通过函数 PostMessage 和PostThreadMessage 把 消息投递到其它线程的队列中去。
应 用程序可通过函数GetMessage 从它的队列中移走一条消息,应用程序还可用函数PeekMessage 来 检查队列中的某个消息但并不移走它,这个函数用有关这条消息的信息填充MSG 结构。
把一条消息从它的队列中移走后.应用程序可用函数DispatchMessage 指 导windows系统把这条消息发送到窗口过程进行处理。DispatchMessage 利用前面调用函数GetMessage 或PeekMessage 时 填充的MSG 结构的指针,把窗口句柄、消息标识及两个消息参数传给窗口过程,但它并不传送时间或鼠标光标的位置.应用 程序可以在处理一条消息时,通过调用函数GetMessageTime 和GetMessagePos 来 获取这些信息。
一个线程可以 用函数WaitMessage 当他没有其他消息在其队列里时,产生对其他线程的控制。此函数将终止线程,直到一个新消 息被放入该线程的消息队列里,然后返回。
你 可以调用函数SetMessageExtraInfo 来设置当前线程消息队列的附加信息。是和当前线程的消息队列联系 的32位值。用户可以用函数GetMessageExtraInfo 来获得附加信息,该信息将会保留到下次调用函数GetMessage 或PeekMessage 之 前。
非排队消息
非 排队消息是直接发送到目标窗口过程的,而不通过系统消息队列和线程消息队列。windows系统一般通过发送非排队消息把影响某窗口的事件通知窗口。例 如,如果用户激活一个新的应用程序窗口.windows系统就会向该窗口发送一系列的消息,包括:WM_ACTIVATE ,WM_SETFOCUS 和WM_SETCURSOR ,这些消息分别通知窗口: 它被激活了;将通过这个窗口进行键盘输入;鼠标已移到这个窗口边 框的里面了 。非排队消息也有可能发生在 应用程序调用一个windows系统函数时,例如,在应用程序用函数SetWindowPos 来移动一个窗口之 后,windows系统发送一条WM_WINDOWPOSCHANGED 消息。
应用程序是调用函数SendMessage 、SendNotifyMessage 或SendDlgItemMessage 发 送消息的。
消息处理
应用程序必须删除和处理投递到它的线 程消息队列中的消息,单一线程的应用程序一般是在它的WinMain函数中使用一个消息环来删除消息,并把消息发送到相应的窗口过程进行处理。具有多重线 程的应用程序在创建窗口的每一个线程中使用一个消息环,下一节将讲述消息环是如何工作的,另外还解释了窗口过程的一般规则。
消息环
一个简单的消息环含有一个对下列函数的调 用:GetMessage, TranslateMessage和DispatchMessage。函数GetMessage从队列中检取一条消息并把它复制到一个MSG结构