3.01 消息队列

概念

消息队列是用于存放消息的队列。

消息在队列中先入先出。

所有窗口程序都具有消息队列。

程序(GetMessage)可以从队列中获取消息。

分类

系统消息队列: 由系统维护的消息队列。存放系统产生的消息,例如鼠标、键盘等。

程序消息队列: 属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护。

消息会发送到系统消息队列, 然后由系统分发到各个程序的消息队列, 再由程序的GetMessage获取

PostMessage -> 系统队列 -> nMsg.hwnd(句柄) -> 窗口数据的内存 -> hIns(实例) -> 对应程序 -> 该程序的GetMessage -> TranslateMessage -> DispatchMessage -> WndProd

消息和消息队列

● 消息和消息队列的关系

  1. 当鼠标、键盘产生消息时,会将消息存放到系统消息队列
  2. 系统会根据存放的消息,找到对应程序的消息队列。
  3. 将消息投递到程序的消息队列中。

● 分类︰

队列消息: 消息的发送和获取,都是通过消息队列完成。 非队列消息: 消息的发送和获取,是直接调用消息的窗口处理(窗口处理函数)完成。

●队列消息

消息发送后,首先放入队列, 然后通过消息循环,从队列当中获取。

GetMessage: 从消息队列中获取消息 PostMessage: 将消息投递到消息队列

常见队列消息: WM_PAINT、键盘、鼠标、定时器。WM_QUIT(必须进队列)

●非队列消息

消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用处里函数,完成消息.

SendMessage: 直接将消息发送给窗口的处理函数,并等候处理结果。 常见消息: WM_CREATE(不能进队列)、WM_SIZE等。

深谈 GetMessage

●在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(HWND,ID范围),不满足条件就不会取出消息,否则从队列取出消息返回。

●如果程序(线程)消息队列没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程序消息队列中。

●如果系统消息队列也没有消息,检查当前进程的所有窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生WM_PAINT消息 ,取得消息返回处理。

●如果没有重新绘制区域,检查定时器如果有到时的定时器,产生WM_TIMER,返回处理执行。

●如果没有到时的定时器,整理程序的资源、内存等等。

●GetMessage会继续等候下一条消息。PeekMessage会返回FALSE,交出程序的控制权。

●注意:GetMessage如果获取到是WM_QUIT,函数会返回FALSE。

WM_PAINT

产生时间︰当窗口需要绘制的时候(并且GetMessage无消息可抓时)。

附带信息: wParam 和 lParam 均为 0。

专职用法∶用于绘图。

窗口无效区域︰需要重新绘制的区域。

  1. BOOL InvalidateRect(
  2. HWND hWnd, //窗口句柄
  3. CONST RECT* lpRect, //区域的矩形坐标 NULL代表全部重新绘制
  4. BOOL bErase //重绘前是否先擦除
  5. );

绘图步骤

  1. 1>开始绘图
  2. HDC BeginPaint(
  3. HWND hwnd,//绘图窗口
  4. LPPAINTSTRUCT IpPaint//绘图参数的BUFF
  5. );返回绘图设备句柄HDC
  6. 2>正式绘图
  7. 3>结束绘图
  8. BOOL EndPaint(
  9. HWND hWnd,//绘图窗口
  10. CONST PAINTSTRUCT*lpPaint//绘图参数的指针BeginPaint返回
  11. );
  12. 4.示例
  13. PAINTSTRUCT ps = { 0 };
  14. HDC hdc = BeginPaint(hWnd, &ps);
  15. TextOut(hdc, 100, 100, "hello", 5);
  16. EndPaint(hWnd, &ps);
  17. // 绘图代码, 需要放在处理WM_PAINT消息时调用