11.2.1 WinMain()函数(4)
该函数只需要一个实参:标识特定程序窗口的窗口句柄hWnd。该调用的结果是Windows给程序发送一条请求重画工作区的消息。
4. 处理Windows消息
最后一项需要WinMain()完成的任务是处理Windows为应用程序排好的消息队列。这么说似乎有点儿奇怪,因为前面曾经说过需要WindowProc()函数来处理消息,下面进一步解释。
排队消息与非排队消息
前面介绍的Windows消息概念过于简化。事实上有两种Windows消息。
一种是被Windows放入队列的排队消息,WinMain()函数必须从队列中提取这些消息进行处理。WinMain()函数中做这件事的代码称为消息循环。排队消息包括因用户从键盘输入、移动鼠标以及单击鼠标按钮而产生的消息。来自定时器的消息和请求重画窗口的Windows消息也都是排队消息。
另一种是致使Windows直接调用WindowProc()函数的非排队消息。大量的非排队消息是作为处理排队消息的结果产生的。我们在WinMain()函数内消息循环中所做的事情是从Windows为应用程序排好的消息队列中提取一条消息,然后请求Windows调用WindowProc()函数来处理该消息。为什么Windows不能在需要时直接调用WindowProc()函数呢?当然可以,但只是没有以这种方式工作,原因与Windows对多个同时执行的应用程序的管理方式有关。
消息循环
如前所述,从消息队列中获取消息是使用某种标准机制完成的,该机制在Windows编程(www.cppentry.com)中称为消息泵或消息循环。消息循环的代码如下所示:
- MSG msg; // Windows message structure
- while(GetMessage(&msg, 0, 0, 0) == TRUE) // Get any messages
- {
- TranslateMessage(&msg); // Translate the message
- DispatchMessage(&msg); // Dispatch the message
- }
这部分代码涉及处理每条消息的3个步骤:
GetMessage():从队列中检索一条消息。
TranslateMessage():对检索的消息执行任何必要的转换。
DispatchMessage():使Windows调用应用程序的WindowProc()函数来处理消息。
GetMessage()函数的作用非常重要,因为它对Windows处理多个应用程序的方式具有重大贡献。接下来详细地看一看这个函数。
GetMessage()函数检索应用程序窗口的消息队列中的某条消息,并将与该消息有关的信息存储在第一个实参指向的变量msg。变量msg是MSG类型的struct,包含许多没有在这里访问的不同成员。但为完整起见,下面给出该结构的定义:
- struct MSG
- {
- HWND hwnd; // Handle for the relevant window
- UINT message; // The message ID
- WPARAM wParam; // Message parameter (32-bits)
- LPARAM lParam; // Message parameter (32-bits)
- DWORD time; // The time when the message was queued
- POINT pt; // The mouse position
- };
前面提到的对匈牙利表示法前缀的误解现在可能在wParam成员上成为现实。我们可能认为该成员属于WORD类型(即16位无符号整数),这种想法在早期的Windows版本中是正确的,但现在该成员属于WPARAM类型,它是一个32位整数值。
wParam和lParam成员的确切内容取决于消息的种类。message成员中的消息ID是一个整数值,它可以是一组在windows.h头文件中预定义为符号常量的值之一。普通窗口的消息ID都以WM_开始,典型的例子如表11-3所示。普通窗口消息覆盖了大量不同的事件,并且包括与鼠标和菜单事件、键盘输入以及窗口创建和管理相关的消息。
表 11-3
|
ID
|
描 述
|
|
WM_PAINT
|
应该重画窗口
|
|
WM_SIZE
|
已重新调整窗口大小
|
|
WM_LBUTTONDOWN
|
按下鼠标左键
|
|
WM_RBUTTONDOWN
|
按下鼠标右键
|
|
WM_MOUSEMOVE
|
已移动鼠标
|
|
WM_CLOSE
|
应该关闭窗口或应用程序
|
|
WM_DESTROY
|
正在销毁窗口
|
|
WM_QUIT
|
应该终止程序
|
GetMessage()函数总是返回TRUE,除非该消息是终止程序的WM_QUIT(此时返回值是FALSE),或者发生了错误(此时返回值是-1)。因此,while循环将持续执行,直到产生关闭应用程序的退出消息或者出现错误状态。在这两种情况下,都需要在return语句中将wParam值回传给Windows,来结束程序。
对于为不同于普通窗口的其他窗口类型指定的消息,也有除了WM之外的前缀。
对GetMessage()函数的调用中,第二个实参是某个窗口的句柄,希望为该窗口获取消息。该参数可用来单独地为某一个窗口检索消息。如果该参数像此处这样是0,则GetMessage()函数将检索应用程序的所有消息。这是一种简单的检索该程序所有消息的方法,而不管某个应用程序有多少窗口。它也是最安全的方法,因为我们肯定可以获得应用程序的全部消息。例如,当Windows程序的用户关闭应用程序的窗口时,该窗口是在生成WM_QUIT消息之前关闭的。因此,如果仅仅通过给GetMessage()函数指定窗口句柄来检索消息,则不能检索这条WM_QUIT消息,导致程序不能正常终止。