如果MessageBox()/ related是同步的,为什么我的消息循环不会冻结?

12 c++ winapi multithreading synchronous blocking

为什么如果我MessageBox()在我的消息循环中调用看似同步的Windows函数,循环本身不会像我调用Sleep()(或类似函数)那样冻结?为了说明我的观点,请采用以下骨架WndProc:

int counter = 0;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
             SetTimer(hwnd, 1, 1000, NULL); //start a 1 second timer
             break;
        case WM_PAINT:
             // paint/display counter variable onto window
             break;
        case WM_TIMER: //occurs every second
             counter++;
             InvalidateRect(hwnd, NULL, TRUE); //force window to repaint itself
             break; 
        case WM_LBUTTONDOWN: //someone clicks the window
             MessageBox(hwnd, "", "", 0);
             MessageBeep(MB_OK); //play a sound after MessageBox returns
             break;
        //default ....
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,程序的主要功能是运行计时器并每秒显示计数器的值.但是,如果用户单击我们的窗口,程序将显示一个消息框,然后在关闭该框后发出蜂鸣声.

这里有趣的地方:我们可以告诉它MessageBox()是一个同步函数,因为MessageBeep()在消息框关闭之前不会执行.但是,计时器保持运行,即使显示消息框,窗口也会每秒重新绘制一次.因此,虽然MessageBox()显然是阻塞函数调用,但仍可以处理其他消息(WM_TIMER/ WM_PAINT).这很好,除非我将MessageBox替换为另一个阻塞调用Sleep()

    case WM_LBUTTONDOWN:
         Sleep(10000); //wait 10 seconds
         MessageBeep(MB_OK);
         break;
Run Code Online (Sandbox Code Playgroud)

这完全阻止了我的应用程序,并且10秒内没有消息处理(WM_TIMER/ WM_PAINT未处理,计数器不更新,程序'冻结'等).那么为什么它MessageBox()允许消息处理继续而Sleep()不是呢?鉴于我的应用程序是单线程的,MessageBox()允许此功能的是什么呢?系统是否"复制"我的应用程序线程,这样它可以完成WM_LBUTTONDOWN代码一次MessageBox()完成,同时仍允许原始线程在过渡期间处理其他消息?(那是我没有受过教育的猜测)

提前致谢

CsT*_*mas 10

MessageBox()和类似的Windows API函数未挡住执行,如IO操作或mutexing会做.该MessageBox()函数通常使用"确定"按钮创建一个对话框 - 因此您可以期望自动处理与消息框相关的Windows消息.这是通过它自己的消息循环实现的 - 没有创建新的线程,但是你的应用程序保持响应,因为像Paint这样的选定消息被处理,递归调用你的WndProc()函数,并且由于创建的窗口的模态类型,一些消息不会传输到.

从您WndProc()处理Windows消息直接调用的Sleep()和其他函数实际上会阻止单线程消息循环的执行,不会处理其他消息.