windows程序开始执行后,windows为该程序创建一个消息队列。这个消息队列用来存放该程序可能创建的各种不同的消息。程序中有一小段代码,叫做消息循环,通过GetMessage从队列中取出消息,如果取出的消息是WM_QUIT则返回0终止消息循环。然后通过TranslateMessage判断消息是按键消息则转换消息后放入消息队列中,然后通过DispatchMessage将消息发回windows,让windows发送消息给窗口过程,让窗口过程根据接受到的消息做出相关的处理。直到窗口处理完后将控制返回给windows,DispatchMessage才能返回。其实相关处理是由程序员来完成的,一般来说,windows程序员使用swtich和case结构来确定窗口过程接受的是什么消息,以及如何适当地处理它。窗口过程在处理消息时,必须返回0。窗口过程不予处理的所有消息应该被传给名为DefWindowProc的Windows函数来进行默认的处理。
实际上窗口过程就是一个回调函数,在填写窗口类结构的lpfnWndProc字段来指定。窗口过程既可以在程序中,也可以在动态链接库中。windows发送消息给窗口过程,实质上就是windows调用了窗口过程,将以类型为MSG的结构表示的消息传给窗口过程。窗口根据此消息进行处理,处理完后将控制返回给windows。
GetMessage从队列中取消息,但是如果队列中没有消息GetMessage会挂起线程。
发送给窗口过程的消息分两种,一种是进队的消息,一种是不进队消息,直接发送给窗口过程。进队消息基本上是用户输入 的结果,而不进队消息在很多情况下是来自调用特定的Windows函数,比如CreateWindow, ShowWindow,UpdateWindow。
一个最简单的windows程序的准备工作就是:注册窗口类,创建窗口,然后在屏幕上显示窗口,程序进入消息循环。实际工作就是窗口过程。当发生事件,产生这个事件对应的消息时,这个期间你想让它做什么就是你自己写代码的事情了。
我再以在窗口点击鼠标左键这个事件为例,再讲述下消息处理的过程。
首先,假设你已经建立好了一个窗口。这时,你在这个窗口内点了一下鼠标左键,Windows系统会将这个事件对应的消息放入到系统消息队列里。之后它会自动分辨出这是哪个窗口所接收的消息,并将这个消息放入到该窗口所对应的应用程序消息队列里。
你的应用程序主函数:WinMain()执行到消息循环后,代码是:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GetMessage()函数从应用程序消息队列里边取出“单击鼠标左键”这一消息,返回值不为0,所以进入循环体,第二个函数用来转换某些键盘消息,而我们点的是鼠标,所以在此直接跳过;第三个函数,将该消息发送回Windows,Windows接收到DispatchMessage()函数发送的消息后,它会自动找到应把消息发往的窗口过程,并把消息发送给它。之后,进入WndProc函数。你会感到这是“Windows调用了WndProc()”,所以WndProc()才被称为“回调函数”。
进入WndProc()之后,通过switch()逻辑检测接收的信息并做出相应的处理和操作。例如,单击鼠标左键,由WndProc()函数掌管的窗口应该进行怎样的变化……这些东西要我们自己来写喽。但其中有些东西几乎是固定的。比如收到WM_DESTROY消息后,一般调用PostQuitMessage(0)发送WM_QUIT消息,用来结束消息循环,
但也不一定,前不久我才写过一个双窗口的程序,当关掉一个窗口后,你应当保证另一个窗口不被关闭……
当WndProc()处理完毕后,DispatchMessage()函数才返回,这时,又要从GetMessage()函数开始新一轮的循环啦
附加一张图方便理解: