写窗口过程
DispatchMessage 函数调用消息的目标窗口的窗口过程。窗口过程具有以下特征:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- hwnd 是窗口的句柄。
- uMsg 是消息代码,例如WM_SIZE消息表示窗口调整大小。
- wParam和lParam包含属于该消息的附加数据。确切的含义取决于消息的代码。
LRESULT 是一个整数值,你的程序将返回Windows。它包含了程序的响应到一个特定的消息,这个值的意义取决于消息的代码。CALLBACK 是该函数的调用约定。
一个典型的窗口过程是个大型的switch语句,切换到相应的消息代码,为每个你要处理的消息添加实例。
switch (uMsg)
{
case WM_SIZE: // Handle window resizing
// etc
}
附加的消息数据包含在lParam和wParam参数,
这两个参数都是整数值大小的指针宽度(32位或64位),各自的含义取决于该消息的代码(参数uMsg)。对于每个消息,你需要在MSND上查找消息代码和转换为正确的数据类型参数。通常情况下,数据可以是数值或一个指向结构的指针;某些消息没有任何数据。
比如:以下是WM-SIZE 的陈述文档
- wParam是一个标志,指示窗口是否最大化、最小化、或调整。
- lParam 包含窗口新的宽度和高度的16位值打包为一个32位或64位的值。你需要执行位移动来获取这些值,幸运的是头文件WinDef.h有能够做到这点的辅助宏。
一个典型的窗口处理几十条消息,因此它可以增长得很长。使代码更加模块化的方法之一是把每个消息的逻辑放在一个单独的函数中处理。在窗口过程,计算wParam和lParam参数的正确数据类型,并传递给函数。例如:处理WM_SIZE消息看起来大概会是这样:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam); //获取低位字宏
int height = HIWORD(lParam); //获取高位字宏
//响应消息
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
}
}
void OnSize(HWND hwnd, UINT flag, int width, int height)
{
//处理所需求的尺寸
}
LOWORD和
HIWORD宏从lParam参数中获取16位的宽度和高度值(你可以看一下MSDN文档中每个消息的细节)。窗口过程提取宽度和高度并把值传递给OnSize函数。
缺省消息处理
如果你不在你的窗口过程处理特定消息,通过消息参数直接传给DefWindowProc函数。这个函数据消息类型而执行消息的默认动作。
return DefWindowProc(hwnd, uMsg, wParam, lParam);
在你的窗口过程内避免阻塞
在你的窗口过程处理时,它会阻止任何其它消息在同一线程创建窗口,因此,在你的窗口过程避免冗长的处理。比如:假设你的程序打开一个TCP连接,并无限期的等待服务器响应。如果你在窗口过程内这样做,你的用户界面不会响应,直到请求完成。在这段时间,窗口无法处理鼠标和键盘输入,重绘本身,甚至关闭。
相反,你应该将工作移到另一个线程,使用Windows中内置的多任务处理设施之一:
- 创建一个新线程。
- 使用一个线程池。
- 使用异步I/O调用。
- 使用异步过程调用。