DoModal in MFC

JoachimJogi

Mitglied
Mein Programm stürzt regelmäßig ab (assertion), wenn ich die im DEBUG_Modus bin, RELEASE läuft einwandfrei. Ich habe das Problem zurückverfolgt bis zur ersten "ASSERT(ContinueModal());" Zeile im RunModalLoop.
Jetzt frage ich mich, was hat diese Überprüfung für einen Sinn?
In der Releaseversion wird diese Prüfung nicht vorgenommen, und vor allem: Es ist doch ganz normal, dass ContinueModal irgendwann false liefert, oder etwa nicht?

In meinem Programm wird DoModal für eine andere Klasse aufgerufen, danach in einem anderen Thread ein bisschen gerechnet und anschließend aus diesem "anderen" Thread EndModal aufgerufen.

Ich habe schon stundenlang diesen Microsoft Code analysiert, aber komme zu keiner sinnvollen Verwendung für diese Assertions. Weiß einer Rat?
Danke!


Code:
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 = &AfxGetThread()->m_msgCur;

    // 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 (!AfxGetThread()->PumpMessage())
            {
                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 (AfxGetThread()->IsIdleMessage(pMsg))
            {
                bIdle = TRUE;
                lIdleCount = 0;
            }

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

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

BOOL CWnd::ContinueModal()
{
    return m_nFlags & WF_CONTINUEMODAL;
}

void CWnd::EndModalLoop(int nResult)
{
    ASSERT(::IsWindow(m_hWnd));

    // this result will be returned from CWnd::RunModalLoop
    m_nModalResult = nResult;

    // make sure a message goes through to exit the modal loop
    if (m_nFlags & WF_CONTINUEMODAL)
    {
        m_nFlags &= ~WF_CONTINUEMODAL;
        PostMessage(WM_NULL);
    }
}
 
Zuletzt bearbeitet:
Könnte daran liegen, daß HWNDs immer nur für einen Thread gedacht sind. Du solltest nicht von einem anderen Thread aus etwas mit dem Fenster machen.

Du kannst dir evtl. mit einem PostMessage beheben, auf die Nachricht hin darf der Dialog dann EndDialog aufrufen.

Edit: Geistesblitz, du rufst doch EndModalLoop nicht direkt auf? Immer mit EndDialog arbeiten!
 
hi,
erstmal danke für die Antwort.
nein, ich arbeite natürlich mit EndDialog

Mein Konstrukt sieht so aus
- Main Thread startet Arbeitsthread und ruft dann DoModal von der WaitKlasse auf. Die Waitklasse ist von CDialog abgeleiet.
Irgendwann sendet der Arbeitsthread eine Nachricht (PostMessage) an den MainThread, sodass der MainThread EndDialog von der WaitKlasse aufruft. Dann läuft der MainThread an der Stelle weiter, wo DoModal aufgerufen wurde.

Meiner Meinung nach verletzte ich hier keine hWnds oder sonstwas.

Danke!
 
Hmm, probier mal, das PostMessage direkt an die Waitklasse zu senden, mit Threads muß man da teilweise vorsichtig sein.
 
Zurück