为啥消息框不阻塞线程? [复制]

Posted

技术标签:

【中文标题】为啥消息框不阻塞线程? [复制]【英文标题】:Why doesn't message box block the thread? [duplicate]为什么消息框不阻塞线程? [复制] 【发布时间】:2017-10-23 13:22:11 【问题描述】:

考虑下面的代码 sn-p,在 WM_TIMER 消息上显示一个消息框。

#define IDT_TIMER1 1001

INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
    switch(message) 

        //...

        case WM_INITDIALOG:
        
            //...

            SetTimer(hWnd, IDT_TIMER1, 1000, (TIMERPROC)NULL);

            break;
        
        case WM_TIMER:
        
            int ret = MessageBox(hWnd, L"Cancel operation?", NULL, MB_YESNO);
            if(ret == IDYES) 
                EndDialog(hWnd, 0);
             else 
                // no-op: keep going
            

            break;
        

        //...

        default:
            return FALSE;
    

    return FALSE;

我希望此代码在初始计时器滴答时显示一个消息框,并阻止线程直到用户单击按钮。 实际上会发生消息框在每个计时器滴答声中显示,即使用户没有点击任何按钮。

当我检查线程的调用堆栈时,我看到对DialogProc() 的多次调用,所有调用都停留在调用MessageBox() 的线上(即都在等待用户输入)。

鉴于调用堆栈的状态,DialogProc() 怎么可能一直在 same 线程中被调用,而 MessageBox()尚未返回最后一次打电话给DialogProc()

附:请注意,我不是在问如何完成所需的行为。我只是在寻找洞察力,以了解导致实际行为的“幕后”发生了什么。

【问题讨论】:

【参考方案1】:

MessageBox 启动一个新的Message Loop,除其他外,它可以通过正常的 Windows 回调机制访问并调用您的DialogProc

如果它不这样做,那么像 WM_PAINT 这样的事件将不会得到处理,并且您的应用看起来就像它已经死了(除了消息框)。由于计时器仍在运行,WM_TIMER 事件会在适当的时间排队。

【讨论】:

【参考方案2】:

MessageBox 进入渲染窗口、处理按钮所需的嵌套消息循环。

MessageBox 调用中指定为第一个参数的窗口已被EnableWindow 禁用,但这不会禁用所有消息,因此您仍会收到 WM_PAINT、WM_TIMER 和其他消息。通常它会禁用用户输入:鼠标、键盘,以及使用鼠标调整窗口大小。

这个伪代码展示了 MessageBox 模拟的潜在实现方式:

int MessageBox( HWND owner_hwnd, ... )

    ...
    HWND box_hwnd = CreateWindowEx( ..., owner_hwnd, ... );
    ...
    EnableWindow( owner_hwnd, FALSE );
    ...
    while ( !done )
    
        MSG msg;
        GetMessage( &msg, ... );
        if ( IsDialogMessage( box_hwnd, &msg ) )
            continue;
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    
    ...
    EnableWindow( owner_hwnd, TRUE );
    ...
    DestroyWindow( box_hwnd );
    ...
    return button;

【讨论】:

以上是关于为啥消息框不阻塞线程? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥不显示消息框?

为啥这个组合框不显示项目?

为啥列表框不使用 Visual C++ 6 显示元素?

哪些阻塞操作会导致 STA 线程泵送 COM 消息?

RocketMQ与Dubbo之间线程之间如何阻塞和唤醒

WinForm,消息框怎样显示在窗体正中?