整理一下Windows的消息相关的知识。
- Windows程序设计
与MS-DOS 不同,Windows 应用程序是基于事件(消息驱动的),它们不会显式地调用函数(如C运行时库调用)来获取输入,而是等待windows向它们传递输入。 windows系统把应用程序的输入事件传递给各个窗口,每个窗口有一个函数,称为窗口消息处理函数。
消息可以由系统和应用程序生成。该系统会为每个输入事件产生相应的消息,例如,用户点击鼠标,移动鼠标或滚动条,或是应用程序改变了系统的某些属性,比如说系统更改了字体资源,改变了某个窗口的大小。 不仅如此,应用程序可以生成消息,通告发送消息指定它的窗体去执行某些任务或者是与其他的应用程序交互。
windows系统将消息发送到一个窗口消息处理函数时传递四个参数:窗口句柄,消息标识符,两个DWORD值(消息参数)。 窗口句柄标识了该消息的目的窗口。windows使用它来确定是哪个窗口的的窗口消息处理函数收到该消息。
消息结构体为MSG, 在WINUSER.H中定义如下:
typedef struct tagMSG
{
HWND hwnd ;
UINT message ;
WPARAM wParam ;
LPARAM lParam ;
DWORD time ;
POINT pt ;
}
MSG, * PMSG ;
2 Windows 消息类型
按照分类,Windows消息类型可以分为 系统消息和应用程序消息,以及自定义消息。 消息的总个数为UINT mMessage ,范围为0x0000 - 0xFFFF。
该系统保留了一个消息范围,从0x0000到0x03FF(0x03FF等于WM_USER -1)范围. 这个范围内的值为系统定义的消息。应用程序不能使用这些值作为自己的自定义消息。
从0x0400(数值WM_USER)到0x7FFF的值是为应用程序保留的。应用程序可以使用这个范围内的值来定义自己的消息。
按照是否进入消息队列来划分, 可以分为队列消息 和 非队列消息。
队列化消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP消息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出。队列化消息 还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。
非队列化消息则是其它消息。在许多情况下,非队列化消息来自呼叫特定的Windows函数。例如,当WinMain呼叫CreateWindow时,Windows将建立窗口并在处理中给窗口消息处理程序发送一个WM_CREATE消息。当WinMain呼叫ShowWindow时,Windows将给窗口消息处理程序发送WM_SIZE和WM_SHOWWINDOW消息。当WinMain呼叫UpdateWindow时,Windows将给窗口消息处理程序发送WM_PAINT消息。
队列化的消息是由Windows放入程序消息队列中的。在程序的消息循环中,重新传回并分配给窗口消息处理程序。非队列化的消息在Windows呼叫窗口时直接送给窗口消息处理程序。也就是说,队列化的消息被「发送」给消息队列,而非队列化的消息则「发送」给窗口消息处理程序。任何情况下,窗口消息处理程序都将获得窗口所有的消息--包括队列化的和非队列化的消息。
3 系统消息队列和应用程序消息队列
windows维护着一个系统消息队列,以及分别为每个GUI线程维护一个各自的线程消息队列。为了避免非GUI线程的创建线程消息队列的开销,所有线程创建初始化时,均不创建消息队列。只有当线程第一次调用GDI函数时,系统才会为线程创建消息队列。所以那些非GUI线程是没有消息队列的。
应用程序中含有一段称作“消息循环”的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。
流程,如下图所示
4 . SendMessage()与PostMessage() 的一些简单区别
4.1 线程内SendMessage只是简单的调用指定窗口的窗口过程
4.2 线程间SendMessage时,发送线程不可能直接调用目标窗口的窗口过程,因为发送线程无法运行在接收线程的地址空间中。因此实际过程是发送线程挂起,然后由另外的线程处理消息。过程是:
首先发送的消息被追加到接收线程的发送消息队列中(send-message queue),并设置线程的QS_SENDMESSAGE标志。这个队列跟邮递消息队列(post-message queue,即之前所谓的消息队列)是并列的,之间没有关系
4.3 PostMessage()将消息直接加入到应用程序的消息队列中, 这个应该是邮寄消息队列(post-message queue),不等程序返回就退出;
如下的图虽然不严谨, 但是比较好的说明了 线程内的SendMessage和PostMessage之间的区别