由于CWnd :: RunModalLoop中的空闲检查,未显示模式MFC对话框 [英] Modal MFC dialog not shown due to idle checks in CWnd::RunModalLoop
问题描述
在下面,我将源放置在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屋!