【问题标题】:How can a dialog become responsive while waiting for a call to DoModal() to return?在等待对 DoModal() 的调用返回时,对话框如何变得响应?
【发布时间】:2023-03-11 17:37:01
【问题描述】:

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

例如:

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

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

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

【问题讨论】:

  • 这似乎不是 Windows API 代码。您能否更新标签以包含正在使用的框架?
  • 对不起,这是 MFC。添加标签。
  • 我的水晶球说某处有代码,由 COM 流量激活,调用 EnableWindow()。这就是父窗口可以再次交互的方式。
  • @HansPassant 是模态对话框,通过在显示时禁用父窗口并在隐藏时启用它并没有更复杂的方法来真正建立它们的模态?
  • 基本上。但他们也泵出一个消息循环,这就是它在 OnButton() 上阻塞的原因。 MFC 做的有点不一样,具体细节不记得了。

标签: winapi com mfc modal-dialog


【解决方案1】:

您可以创建一个无模式对话框并使用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);

但是在这个例子中,如果用户点击确定/取消然后你不知道它,你必须覆盖OnOK()/OnCancel然后发送消息到父窗口/对话框,处理消息,然后手动销毁对话框。

【讨论】:

    【解决方案2】:

    对话框有自己的消息泵/循环,并且在调用内部有一个循环,它不断接收和分派窗口消息。这包括工作窗口接收并转换为您看到的 COM 回调的 COM 相关消息。一旦对话框关闭,相应的窗口就会被销毁,函数退出循环并将控制权返回给您的代码。

    也就是说,在不立即将控制权返回给您的代码的情况下,窗口消息调度仍会像往常一样继续工作,并且 UI 是响应式的。

    MSDN:

    ...该函数显示对话框,禁用所有者窗口,并启动自己的消息循环以检索和调度对话框的消息。

    当对话框过程调用 EndDialog 函数时,DialogBox 销毁对话框,结束消息循环,启用所有者窗口(如果之前启用),并在调用 EndDialog 时返回对话框过程指定的 nResult 参数。

    【讨论】:

    • 这是有道理的,并且似乎在暗示(正如 Hans cmets 在这个问题上)这是一个完全正常的 API 调用,而不是什么“魔法”?
    • 是的,总体而言这是正常行为,因为它以不希望的方式启用您的窗口,您可能希望在相关位置(例如 WM_ENABLE 处理程序)设置断点以找出调用堆栈上的确切内容那时,也许有一些 COM 回调,您可能希望在其中检查 IsWindowEnabled 并在所有者窗口因模式对话框而被禁用时跳过该事件。
    猜你喜欢
    • 2013-02-12
    • 1970-01-01
    • 2016-12-28
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    • 1970-01-01
    相关资源
    最近更新 更多