编写窗口过程(Writing the Window Procedure)
DispatchMessage函数调用作为消息目标窗口的窗口过程。窗口过程具有以下签名(signature)。
C++
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
4个参数:
- hwnd 是对应窗口的一个句柄。
- uMsg是消息代码;例如, WM_SIZE消息表明窗口被调整了大小。
- wParam和lParam包含与消息相关的其他数据。确切的含义取决于消息代码。
LRESULT是你的程序返回给Windows的一个整数值。它包含程序对特定消息的响应。这个值的含义取决于消息代码。CALLBACK是函数的调用约定。
一个典型的窗口过程就是一个大型的switch语句,它会打开消息代码。为要处理的每个消息添加case。
C++
switch (uMsg) { case WM_SIZE: // Handle window resizing // etc }
消息的其他数据包含在lParam和wParam参数中。这两个参数都是指针宽度(32位或64位)大小的整数值。它们的含义取决于消息代码(uMsg)。对于每个消息,您需要在MSDN上查找消息代码,并将参数转换为正确的数据类型。通常数据要么是数值,要么是指向结构的指针。有些消息没有任何数据。
例如, WM_SIZE消息的文档表明:
- wParam是一个标志,指示窗口是否被最小化、最大化或调整大小。
- lParam包含窗口的新宽度和高度,将16位值打包成一个32位或64位数字。您将需要执行一些位移位(bit-shifting)来获取这些值。幸运的是,头文件WinDef.h包含执行此操作的辅助宏。
一个典型的窗口过程(window procedure)处理几十条消息,因此它可以长得相当长。使代码更模块化的一种方法是将处理每个消息的逻辑放在一个单独的函数中。在窗口过程中,将wParam和lParam参数转换为正确的数据类型,并将这些值传递给函数。例如,要处理WM_SIZE消息,窗口过程如下所示:
C++
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_SIZE: { int width = LOWORD(lParam); // Macro to get the low-order word. int height = HIWORD(lParam); // Macro to get the high-order word. // Respond to the message: OnSize(hwnd, (UINT)wParam, width, height); } break; } } void OnSize(HWND hwnd, UINT flag, int width, int height) { // Handle resizing }
LOWORD 和HIWORD 宏从lParam获得16位的宽度和高度值。(您可以在MSDN文档中查找每个消息代码的详细信息)。窗口过程提取宽度和高度,然后将这些值传递给自己编写的OnSize函数。
默认消息处理(Default Message Handling)
如果不处理窗口过程中的特定消息,则将消息参数直接传递给DefWindowProc函数。此函数执行消息的默认操作,该操作因消息类型而异。
C++
return DefWindowProc(hwnd, uMsg, wParam, lParam);
避免窗口过程中的瓶颈(Avoiding Bottlenecks in Your Window Procedure)
在执行窗口过程时,它会阻止(block)在同一线程上创建的窗口的任何其他消息。因此,避免在窗口过程中进行冗长的处理。例如,假设您的程序打开一个TCP连接并无限期地等待服务器响应。如果您在窗口过程中这样做,那么在请求完成之前,您的UI将不会响应。在此期间,窗口无法处理鼠标或键盘输入、重新绘制自身,甚至无法关闭。
相反,您应该将工作转移到另一个线程,使用Windows内置的多任务处理设施之一:
- Create a new thread. 创建新线程
- Use a thread pool. 使用线程池
- Use asynchronous I/O calls. 使用异步I/O调用
- Use asynchronous procedure calls. 使用异步程序调用
原文地址:https://www.cnblogs.com/wainzhang/p/9370917.html