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