VC中的定时器与消息机制

    用VC编程,最重要的是要熟悉消息机制。但这一点好像并不是那么容易搞懂,至少现在我还不是完全明白,只有遇到问题时才想办法把它查清楚。
     案例:通过SetTimer设置一个定时器,在OnTimer 中,设置弹出一个对话框,如MessageBox("Hello")。你会发现对话框会不断的弹出,而不是阻塞在那里?如果你对这个问题很清楚,并且不会认为这是多线程机制,那恭喜你,你一定对Windows消息机制比较熟悉,也比我知道的要多,那你就多给我挑挑毛病吧。否则,希望我的这篇文章能对你有所帮助。
    首先说明,这个结果绝对不是多线程引起的。有同学开始认为是多线程,每次OnTimer 调用单独开一个线程。但我打开任务管理器跟踪发现线程并没有增加。于是我上csdn请教高手,经过一个下午的讨论,才算弄明白,其核心问题还在于消息机制。
    如果用Windows API写过程序,你应该明白在WinMain中有一个消息循环,不断的取消息,转换,重新发送消息,代码如下:
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
   if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
   {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
}
    通过GetMessage得到一个消息,如果没有消息,则会阻塞到这里。这个消息从哪里来?操作系统。操作系统为每个线程创建一个消息队列(在收到第一个消息时真正创建),而每个线程可以包括多个窗口。也就是说,这个消息队列包括了该线程中所有的窗口消息。因此,通过GetMessage获取消息时,当第二个参数为NULL时,会将同线程中其他窗口的消息也得到。然后进行消息转换,首先转换快捷键为相应的消息,然后转换你的键盘操作,通过消息转换将其解析为到底是输入字符,还是控制键。转换完成后,再通过DispatchMessage来分发消息。分发给谁?操作系统。操作系统收到消息后,调用消息所属窗口的WndProc函数,根据消息的类型进行处理。处理完成后,操作系统将控制权再转交给程序,完成Dispatch,继续进行消息循环。
    这里需要注意的就是,每个窗口的消息循环不只是处理本窗口的消息,也将同线程下其他窗口的消息也处理掉了。 这就是为什么当OnTimer 弹出一个对话框后还可以继续弹出对话框,是因为弹出的MessageBox本身的消息循环接替了上一个窗口循环的工作。 如此递归调用,这也是为什么消息机制支持嵌套调用。这里有一个问题,DispatchMessage为什么不由程序本身来调用,而非要经过操作系统?这就是出于便捷考虑,如果直接处理,那么一个窗口必须有权限访问其他窗口的处理函数,不然怎么实现处理其他窗口的调用呢?这就是回调函数的优点。
    另外一个问题,程序在执行消息时,会不会在一条消息处理没有完毕时,就去处理下一条?比如不断的调用OnTimer ?答案是不会,除非在处理函数中有一个消息循环,类似于本文的案例。否则,只可能在一条消息处理完毕后,才执行下一条。
    OnTimer 的定时是不精确的,并且WM_TIMER消息的优先级非常低,总是添加到消息队列的尾部。并且同一个定时器消息只会在队列中出现 一次 ,类似于WM_PAINT消息。你不用担心在OnTimer 处理函数中执行太久后收到一堆的WM_TIMER消息,但你也要注意,你的WM_TIMER消息已经丢失了一些。
    OnTimer 本身的使用这里就不说了,网上的例子很多,希望看到这篇文章能有所收获!

posted @ 2009-04-08 17:02  dzqabc  阅读(1827)  评论(0编辑  收藏  举报