Windows 消息

来源:互联网 发布:jy零食淘宝店 编辑:程序博客网 时间:2024/06/04 08:59

 

窗口过程(winproc), 是程序处理消息的地方, 但是不是由程序自己调用, 而是由Windows调用通过检索窗口注册类得到窗口过程函数指针(wndclass.lpfnWndProc  = WndProc)。 Mfc对此的封装可谓是两万五千里长征。要了解mfc的处理, 先得弄清楚sdk吧。

 

消息能够被分为「队列化的」和「非队列化的」。简单讲非队列化消息直接发送给窗口过程,而队列化消息先被送进程序消息列队,程序通过消息循环检索消息,然后调用dispatchmessage , 一旦调用dispatchmessage, 程序进入windows管态, 由windows调用适当的窗口过程。

 

队列化消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP消息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出。队列化消息还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。

 

非队列化消息则是其它消息。在许多情况下,非队列化消息来自调用特定的Windows函数。如CreateWindow时发送 WM_CREATE.

 

 

消息循环如下:

 

While (GetMessage(&msg, NULL, 0, 0)

{

TranslateMessage (&msg) ; // 键盘鼠标消息转换
       
    DispatchMessage (&msg) ;

}

 

NULL – 接收该线程内的所有消息。

 

如果函数取得WM_QUIT之外的其他消息,返回非零值。如果函数取得WM_QUIT消息,返回值是零。即接收到WM_QUIT, 程序退出循环, 程序就此了结一生。

 

调用GetMessage程序会挂起,即交出时间片,由windows接管, 直到有消息过来。

 

值得注意的是另一个函数PeekMessage. 先看代码

 

while (TRUE)
       
{
       
    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))  PM_REMOVE删除消息
       
    {
       
            if (msg.message == WM_QUIT)
       
                   break ;
       
            TranslateMessage (&msg) ;
       
            DispatchMessage (&msg) ;
       
    }
       
    else
       
    {
       
            // 完成某些工作的其它行程序
       
    }
       
}
.

 

调用PeekMessage将立刻返回, 如果列队中有消息返回TRUE, 否则FALSE。所以检查WM_QUIT是必须的. 如果列队中没有消息, 不像GetMessage, 程序可以稍稍运行一段时间, 这就是游戏渲染的时机了。

 

无论GetMessage, 还是PeekMessage, 多是无法删除WM_PAINT消息. 那不是列队中只要有一个WM_PAINT, 程序就无法退出了吗? 实际上从队列中删除WM_PAINT消息的唯一方法是令窗口显示区域的失效区域变得有效,这可以用ValidateRect和ValidateRgn或者BeginPaint和EndPaint对来完成. MFC 对此进行了封装, 以至于我们看不到BeginPaint. 有兴趣可以去看一下CPaintDC的源码。

 

而InvalidateRect 使显示的一个矩形区域失效, 并可能会产生WM_PAINT消息.  为什么是可能会呢? 因为绘制操作是一种低优先级操作, 尽可能的拖后. 程序列队不为空时, InvalidateRect调用将不会产生WM_PAINT, 而是累加失效矩形区域, 等到空时,产生WM_PAINT消息, 一次性完成绘制操作。 所以计时器中调用InvalidateRect 有可能不能如你所愿。解决的方法是 InvalidateRect 后, 调用一个Send一个WM_PAINT(SendMessage, 过会儿讲)或者调用更方便和强大的函数的UpdateWindow和RedrawWindow,UpdateWindow会检查窗口的失效矩形区域,当其不为空时才发送WM_PAINT消息。

 

WM_TIMER 消息低优先级, 列对中只能有一个, 所以不要祈求过高的精度。WM_TIMER来绘制动画, 我认为不好。

 

 

SendMessage 如果指定的窗口通过调用线程被创建,则窗口过程作为子程序被立即调用。如果指定的窗口通过调用不同线程被创建,则系统切换到该线程并调用适当的窗口过程。线程间的消息只有在接收线程执行消息检索代码时才被处理。发送线程将被阻塞到接收线程处理完消息为止。非列队的。

 

PostMessage只把消息放入队列,不管程序是否处理都返回,然后继续执行,这是个异步消息投放函数。

 

总之, 列队内消息, 排序进行处理。 非列队的立刻处理掉。

 

就此打住!

 

 

原创粉丝点击