由于CWnd :: RunModalLoop中的空闲检查,未显示模式MFC对话框 [英] Modal MFC dialog not shown due to idle checks in CWnd::RunModalLoop

查看:274
本文介绍了由于CWnd :: RunModalLoop中的空闲检查,未显示模式MFC对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面,我将源放置在CWnd::RunModal上,这是调用CDialog::DoModal时运行的消息循环-它作为嵌套的消息循环接管,直到对话框结束.

Below I've put the source to CWnd::RunModal, which is the message loop run when you call CDialog::DoModal - it takes over as a nested message loop until the dialog is ended.

请注意,在几个特殊情况下,仅当消息队列空闲时才调用ShowWindow.

Note that with a couple of special case exception ShowWindow is only called when the message queue is idle.

在某些情况下,当调用DoModal时,这会导致对话框在很多情况下不会出现.如果我调试代码并放入断点,我会看到直到此时才达到阶段1 循环.但是,如果我无模式地创建相同的对话框(调用Create,然后立即出现ShowWindow),但这将是一个笨拙的更改,只修复了一个不了解它的错误.

This is causing a dialog not to appear for many seconds in some cases in our application when DoModal is called. If I debug into the code and put breakpoints, I see the phase 1 loop is not reached until this time. However if I create the same dialog modelessly (call Create then ShowWindow it appears instantly) - but this would be an awkward change to make just to fix a bug without understanding it well.

有没有办法避免这个问题?也许我可以在某个时候显式调用ShowWindow或发布一条消息以触发空闲行为?我读了旧的新事物-模式" 内容丰富,但没有回答这个问题,而且我没有找到成功的解决方法,只能在网上很少提及它.

wincore.cpp:CWnd :: RunModalLoop

Is there a way to avoid this problem? Perhaps I can call ShowWindow explicitly at some point for instance or post a message to trigger the idle behaviour? I read "Old New Thing - Modality" which was very informative but didn't answer this question and I can only find it rarely mentioned on the web, without successful resolution.

int CWnd::RunModalLoop(DWORD dwFlags)
{
    ASSERT(::IsWindow(m_hWnd)); // window must be created
    ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state

    // for tracking the idle time state
    BOOL bIdle = TRUE;
    LONG lIdleCount = 0;
    BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
    HWND hWndParent = ::GetParent(m_hWnd);
    m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
    MSG *pMsg = AfxGetCurrentMessage();

    // acquire and dispatch messages until the modal state is done
    for (;;)
    {
        ASSERT(ContinueModal());

        // phase1: check to see if we can do idle work
        while (bIdle &&
            !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
        {
            ASSERT(ContinueModal());

            // show the dialog when the message queue goes idle
            if (bShowIdle)
            {
                ShowWindow(SW_SHOWNORMAL);
                UpdateWindow();
                bShowIdle = FALSE;
            }

            // call OnIdle while in bIdle state
            if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
            {
                // send WM_ENTERIDLE to the parent
                ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
            }
            if ((dwFlags & MLF_NOKICKIDLE) ||
                !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
            {
                // stop idle processing next time
                bIdle = FALSE;
            }
        }

        // phase2: pump messages while available
        do
        {
            ASSERT(ContinueModal());

            // pump message, but quit on WM_QUIT
            if (!AfxPumpMessage())
            {
                AfxPostQuitMessage(0);
                return -1;
            }

            // show the window when certain special messages rec'd
            if (bShowIdle &&
                (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
            {
                ShowWindow(SW_SHOWNORMAL);
                UpdateWindow();
                bShowIdle = FALSE;
            }

            if (!ContinueModal())
                goto ExitModal;

            // reset "no idle" state after pumping "normal" message
            if (AfxIsIdleMessage(pMsg))
            {
                bIdle = TRUE;
                lIdleCount = 0;
            }

        } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
    }

ExitModal:
    m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
    return m_nModalResult;
}

推荐答案

要回答我自己的问题,我发现的解决方案是显式调用以下两种方法:

So to answer my own question, the solution I found was to explicitly call the following two methods:

ShowWindow(SW_SHOWNORMAL);
UpdateWindow();

CWnd::RunModalLoop应该调用这些,但是仅当它检测到消息队列为空/空闲时才调用它们.如果没有发生,则该对话框存在并阻止输入其他窗口,但不可见.

CWnd::RunModalLoop is supposed to call these, but only when it detects the message queue is empty/idle. If that doesn't happen then the dialog exists and blocks input to other windows, but isn't visible.

从跟踪消息中,我发现WM_ACTIVATE是在发生问题之前发送的最后一条消息,因此我在Dialog类中添加了OnActivate()处理程序.

From tracking messages I found WM_ACTIVATE was the last message being sent before things got stuck, so I added an OnActivate() handler to my Dialog class.

这篇关于由于CWnd :: RunModalLoop中的空闲检查,未显示模式MFC对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆