【问题标题】: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()

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

【问题讨论】:

    标签: c++ multithreading winapi


    【解决方案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;
      }
      

      【讨论】:

        猜你喜欢
        • 2020-08-22
        • 1970-01-01
        • 1970-01-01
        • 2020-08-06
        • 1970-01-01
        • 1970-01-01
        • 2021-10-19
        • 2016-06-26
        • 2021-08-29
        相关资源
        最近更新 更多