消息处理
1、一般在窗口过程中使用switch和case结构来确定窗口过程接收到的是什么消息,以及如何处理它,
注意:<1>窗口过程处理消息后,必须返回0;
<2>窗口过程不予处理的所有消息应该被传递给DefWindowProc函数,从DefWindowProc返回的值,再由窗口过
程返回,如:return DefWindowProc(hwnd, message, wParam, lParam);
2、消息介绍
<1>WM_CREATE
这是窗口过程接收的第一个消息,也可能是其处理的第一个消息,
消息触发:Windows在WinMain中处理CreateWindow函数时,windows会调用应用程序的窗口过程(注意:此时WM_CREATE消息不是通过消息循环进入窗口过程的),将窗口过程的第一个参数设置为刚设定的窗口句柄,将第二个参数设置为WM_CREATE,窗口过程执行完成后,将控制传回给Windows,Windowss然后从CrateWindow函数调用中返回到应用程序的WinMain函数中,继续执行WinMain中下面的代码。
注意:通常,窗口过程在处理WM_CREATE消息期间,进行一次窗口初始化。
<2>WM_PAINT
当窗口显示区域的一部分显示内容或者全部显示内容变为无效,以致于必须“更新画面”时,将会由这个消息通知应用程序,
什么时候窗口的显示区域会变得无效?
1* 在最初创建窗口的时候,这时整个显示区域都是无效的,因为程序还没有在窗口上画任何东西,窗口第一次接收到WM_PAINT消息(通常发生在WinMain中调用UpdateWindow时)指示窗口过程在屏幕上画一些东西。
2* 在使用者改变窗口大小后,显示区域的显示内容重新变为无效。
3* 当使用者将窗口最小化,然后再次将窗口恢复为以前的大小时,windows不会保存显示区域的内容,而是令窗口无效,发送WM_PAINT消息给窗口过程,并自动恢复其窗口的大小。
4* 在移动窗口以致其与其他窗口相互重叠时,Windows不保存一个窗口被另一个窗口所遮盖的部分,当这一部分不再被遮盖之后,它就被标志为无效,窗口过程接收到一个WM_PAINT消息,以更新窗口内容。
5* 应用程序自己修改窗口的内容。
发生以下几种事件之一时,窗口过程将接收到一个WM_PAINT消息:
<1>在使用者移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见;
<2>使用者改变窗口的大小(如果窗口类别中有CS_HREDRAW和CS_VREDRAW);
<3>程序使用ScrollWindow和ScrollDC函数滚动显示区域的一部分;
<4>程序使用InvaldateRect或InvalidateRgn函数刻意产生WM_PAINT消息;
<5>在某些情况下,显示区域的一部分被临时覆盖,Windows试图保存一个显示区域,并在以后恢复它,但这不一定能成功,在以下情况,windows可能发送WM_PAINT消息:
Windows擦除覆盖了部分窗口的对话框或消息框;
功能表下来出来,然后被释放;
显示工具提示消息;
特别注意:在某些情况下,Windows总是保存它所覆盖的显示区域,然后恢复它,这些情况是:
鼠标,光标划过显示区域;
图示拖过显示区域。
3、WM_DESTROY
这一消息指示:Windows正在根据使用者的指示关闭窗口,该消息通常是使用者单击Close按钮或者在程序的系统菜单中选择Close时发生的。
窗口与消息总结:
1、在Windows程序设计中,程序的所有实际动作都发生在窗口过程中,Windows程序的一切动作都是在回应发送给窗口过程的消息。
Windows给窗口发送消息的实际含义是Windows调用应用程序的窗口过程函数,并将消息参数传递给该函数。
2、关于队列化消息与非队列化消息:
消息分为队列化的和非队列化的,队列化的消息是指由WIndows放入到应用程序的消息队列中的,在程序的消息循环中,重新传回并分配给窗口过程;非队列化的消息是在Windows呼叫窗口时,直接发送给窗口过程的消息,即:队列化的消息要经过消息循环,再传递给窗口过程;非队列化的消息直接传递给窗口过程。
注意:任何情况下,窗口过程都获得窗口的所有消息,包括队列化的和非队列化的,窗口过程是窗口的消息处理中心。
队列化消息基本上是使用者输入的结果,如WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_MOUSE, WM_LBUTTONDOWN等,还包括WM_TIMER, WM_PAINT, WM_QUIT等消息。
非队列化消息是其他一些消息,许多情况下,非队列化消息来自呼叫特定Windows函数。例如,WinMain中调用CreateWindow时,windows在其处理中直接给窗口过程发送的WM_CREATE消息;当WinMain中调用ShowWindow时,Windows给窗口发送的WM_SIZE和WM_SHOWWINDOW消息;当WinMain函数调用UpDadeWindow函数时,Windows给窗口过程发送的WM_PAINT消息等。
3、进一步理解窗口过程(重点)
从窗口过程的角度看,消息是以一种有序的、同步的方式进出窗口过程函数的,窗口过程可以处理也可以不处理。
注意:
<1>、虽然Windows程序可以多执行序执行,但是消息循环和窗口过程不是并发执行的。
每个执行序的消息队列只为窗口过程在该执行序中执行的窗口处理消息,当一个消息循环从其消息队列中接收一个消息,然后调用DispatchMessage将消息发送给窗口过程时,直到窗口过程将控制传回给windows, DispatchMessage 才结束执行。也就是说,在消息循环进行下一个循环从消息队列中取出消息之前,上一个取出的消息已经被窗口过程处理完成了。
<2>、虽然消息不能并发处理,但是消息可以嵌套处理。
窗口过程是可重入的,例如窗口过程可以在处理某个消息A时,调用一个函数f来给窗口过程发送另一个消息B,这时候,窗口过程必须在这个函数f返回之前完成对第二个消息B的处理,在函数f返回后,窗口过程将继续完成对第一个消息A的处理,(类似于函数的嵌套调用)。
<3>、注意由于<2>,引起的问题。
例如,在窗口过程处理某个消息时,定义一个static局部变量C,然后调用一个WIndows函数,在这个函数返回时,前一个静态变量C的值有可能已经改变。(可能调用的这个函数产生了另一条消息D,并且窗口过程在处理消息D时,改变了static局部变量C的值),因此,当窗口过程必须保存它从消息中获得的信息,并要在处理另一个消息时使用这些信息,这些信息可以用窗口的static变量或全局变量来存储。
4、特别注意:虽然窗口过程函数是我们自己编写的,但是别忘了最后还有DefWindowProc部分的工作,应该将它考虑为我们消息处理过程的一部分。