在等待调用 DoModal() 到 return 时,对话框如何变得响应?

How can a dialog become responsive while waiting for a call to DoModal() to return?

对话框上的按钮会导致创建子对话框,并以模态方式显示。

例如:

void ParentDialog::OnButton()
{
 ChildDialog dlg;
 int ret = dlg.DoModal();
}

如预期的那样,父对话框最初没有响应。但是,子对话框也会对服务器模块进行 COM 调用,这会导致服务器对父对话框进行 COM 调用...以更新显示的数据等。在一种情况下,这会导致父对话框突然变得响应再次即使子对话框仍在屏幕上。现在可以与两个对话框进行交互,即使父对话框仍在耐心等待 OnButton() 到 return。

怎么会这样?我正在搜索代码,但有什么我应该寻找的具体内容吗?

对话框有自己的消息 pump/loop 并且在调用内部有一个循环,它不断接收和发送 window 消息。这包括与 COM 相关的消息 worker windows 接收并转换为您看到的 COM 回调。对话框关闭后,相应的 windows 被销毁,函数退出循环并 returns 控制您的代码。

也就是说,如果不立即将控制权返回给您的代码,window 消息调度仍会照常工作并且 UI 会响应。

MSDN:

... The function displays the dialog box, disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

When the dialog box procedure calls the EndDialog function, DialogBox destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns the nResult parameter specified by the dialog box procedure when it called EndDialog.

您可以创建一个无模式对话框并使用RunModalLoop等待对话框完成,有点类似于DoModal()

void CMyWnd::foo()
{
    static BOOL isOpen = FALSE;
    if (isOpen) return;//optional, prevents opening multiple dialogs

    CDialog dlg;
    dlg.Create(IDD_DIALOG1, this);
    dlg.ShowWindow(SW_SHOW);
    isOpen = TRUE;

    int result = dlg.RunModalLoop(0);
    dlg.DestroyWindow();
    isOpen = 0;

    TRACE("res:%d\n", result);
}

问题: 请注意,在上面的示例中,您可以关闭程序,但对话框仍会打开。你必须强制关闭对话框,上面的函数不处理这个问题。

或者您可以用通常的方式创建无模式对话框:

if (m_Dlg) return;
m_Dlg = new CDialog
m_Dlg.Create(IDD_DIALOG1, this);
m_Dlg.ShowWindow(SW_SHOW);

但是在这个例子中,如果用户点击 OK/Cancel 那么你不知道它,你必须覆盖 OnOK()/OnCancel 然后发送消息给父级 Window/Dialog,处理消息,然后然后手动销毁对话框。