Visual C ++中消息回调函数的执行顺序

时间:2015-07-20 05:09:54

标签: c++ winapi visual-c++ message-queue

我正在开发一个Windows Visual C ++应用程序,它将监视消息泵的各种事件。这是我的主要cpp文件的骨架:

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch(message) {
        case WM_CLIPBOARDUPDATE:
            // handle the update here
    }
}

这是回调函数的骨架:

.

我的简单问题是回调函数是否保证在序列中开始和结束,或者它们是否可能在 parallel 中执行并且有些重叠?换句话说,是否有可能并行执行2次回调函数调用,可能导致竞争条件?或者Windows是否保证每个消息都是串行处理的,一次一个?您可能会提供任何文档或参考资料。

2 个答案:

答案 0 :(得分:4)

窗口消息存储在队列中。每次调用GetMessage时,它都会从队列中删除第一条消息。调用DispatchMessage时会调用您的窗口过程。

所以是的,消息按顺序处理。但是,如果在窗口过程中调用SendMessage,则可能存在一些重叠,因为该函数会绕过消息队列并直接调用窗口过程(而不是将消息放入队列中的PostMessage)。

但这并不意味着窗口过程将并行执行(如同来自多个线程)。 DispatchMessage和SendMessage都不会创建不同的线程来运行窗口过程。

答案 1 :(得分:1)

窗口消息有时存储在消息队列中,有时则不存储。未存储在队列中的窗口消息的示例是WM_ACTIVATE,WM_SETFOCUS和WM_SETCURSOR。其他消息(如WM_PAINT)放在消息队列中。

永远不会在parellel中调用窗口的窗口过程(参见上一个答案)。

消息确实按顺序处理,GetMessage从队列中提取第一条消息。但需要注意的一件重要事情是,消息可以在没有处理的情况下从队列中“消失”。例如,窗口内部为每个窗口维护一个结构(PAINTSTRUCT),在该窗口中它跟踪窗口的无效区域。只要窗口客户区的任何部分无效,Windows就会在消息队列中放置WM_PAINT消息。但是,如果验证了无效区域(例如,调用ValidateRect),Windows实际上会从队列中删除该消息。此外,如果另一个区域被添加到无效区域,Windows不会在队列上放置另一个WM_PAINT消息,它会更新已放置的WM_PAINT消息和更新的区域。