none
MFC Anwendergerüst beendet bialogbasierte Anwendung seltsam RRS feed

  • Frage

  • Hallo Forum

    Ich habe jetzt durch Versuch und Irrtum ein äußerst interessantes Verhalten eines meiner MFC Programme festgestellt.

    Ich habe also ein "einfaches" dialog-basiertes MFC Programmchen erstellt und habe dann in der App klassischerweise folgenden Text:

    m_thread_enabled = true;

    AfxBeginThread(...)

    ...

    CMACDlg dlg;
    m_pMainWnd = &dlg;
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK)
     {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with OK
     }
     else if (nResponse == IDCANCEL)
     {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with Cancel
     }

    m_thread_enabled = false;

    // weitere Destruktionen

    ...

    }

     

    VOR dem Deklarieren des Hauptdialoges starte ich auch ein einige Threads, die ihrerseits in einer Schleife die Variable m_thread_enabled prüfen und sobald ich den Dialog (durch OK oder Cancel) beende, setze ich (siehe oben) die Variable auf false und die Threads beenden sich dann mehr oder weniger schnell auch.

    Soweit so gut. Ich habe jetzt allerdings festgestellt, dass sobald ich den Dialog beende (wie auch immer), der Code nach dem dlg.DoModal() gar nicht mehr ausgeführt wird, die Threads interessanterweise dennoch alle rausgeschmissen werden...allerdings ohne ihre Destruktor-Routinen sauber auszuführen.

    Meine Erklärung ist derzeit nur folgende:

    Indem dem Gerüst in der Zeile m_pMainWnd = &dlg; mitgeteilt wird, dass dies das heilige Hauptfenster ist, wird der gesamte Prozess beendet, sobald dieses Fenster geschlossen wird.

    IST DAS SO? ... oder hab ich etwas Fundamentales übersehen?

     

    Grüße

    FireHeart

    Donnerstag, 12. Mai 2011 07:16

Antworten

  • Jochen hat Recht. Solange nicht von wo anders ExitProcess aufgerufen wird, kann das nciht sein.

    InitInstance wird weiter abgelaufen. Dass mit dem Schließen des "heligen Hauptfenster" bewirkt nur eine einzige zusätzliche Aktion: AfxPostQuitMessage wird ausgeführt! Mehr auch nicht.

    Das wiederum führtdazu dass eine Message Loop (egal wo) terminiert!

    Ein Dialog ist ja eine Spezialität hier, weil das Framewindow nicht dynamisch sondern im Stack liegt und nicht in einem PostNcDestroy auch zersört wird.


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    • Als Antwort markiert Fire-Heart Donnerstag, 12. Mai 2011 08:58
    Donnerstag, 12. Mai 2011 08:07
    Moderator

Alle Antworten

  • So lange Du nicht irgendwo ExitProcess aufrufst, sollte es nicht so sein...


    Jochen Kalmbach (MVP VC++)
    Donnerstag, 12. Mai 2011 07:32
  • Hallo Jochen

    Als ich schließlich begann zu ahnen, was hier läuft, hab ich mal versucht, das Dialog-Fenster NICHT-MODAL zu machen

    m_con_cfg.enabled = true;
    AfxBeginThread(...);
    CMACDlg dlg;
    m_pMainWnd = &dlg;
    dlg.Create();
    while (!dlg.m_want_close) {
    dlg.LookForMessage();
    Sleep(10);
    }
    // POSITION A m_con_cfg.enabled = false;
    //warten bis sich alle Threads sauber beendet haben
    while (m_con_cfg.csc_running || m_con_cfg.ctl_running) {
    dlg.LookForMessage();
    Sleep(10);
    }

    // Andere Destruktionen
    ...

    dlg.DestroyWindow();
    return FALSE;
    Ich starte also alle meine Threads, erzeuge das Dialog-Fenster nicht-modal und bleibe in einer Schleife, bis mir das Fenster sagt (über m_want_close) dass es geschlossen werden will. Dann setze ich die Freigabe fuer die Threads zurueck und warte auch noch, bis sie sich wirklich beendet haben. Ganz am Ende mache ich dlg.DestroyWindow() und das wars...das funktioniert auch prima.
    ABER: Wenn ich dlg.DestroyWindow() an POSITION A schreibe, werden alle Destruktionen NICHT mehr ausgefuehrt.

    Ich kanns ja selber kaum glauben....

    FireHeart

    Donnerstag, 12. Mai 2011 08:06
  • Jochen hat Recht. Solange nicht von wo anders ExitProcess aufgerufen wird, kann das nciht sein.

    InitInstance wird weiter abgelaufen. Dass mit dem Schließen des "heligen Hauptfenster" bewirkt nur eine einzige zusätzliche Aktion: AfxPostQuitMessage wird ausgeführt! Mehr auch nicht.

    Das wiederum führtdazu dass eine Message Loop (egal wo) terminiert!

    Ein Dialog ist ja eine Spezialität hier, weil das Framewindow nicht dynamisch sondern im Stack liegt und nicht in einem PostNcDestroy auch zersört wird.


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    • Als Antwort markiert Fire-Heart Donnerstag, 12. Mai 2011 08:58
    Donnerstag, 12. Mai 2011 08:07
    Moderator
  • > ABER: Wenn ich dlg.DestroyWindow() an POSITION A schreibe, werden alle Destruktionen NICHT mehr ausgefuehrt.

    "Destruktionen" meinst Du die Threads?
    Dann musst Du einen Code haben, der evtl. exit (CRT) aufruft oder sonst was. Wird eine Exception oder ein ASSERT geworfen.
    Was sagt das Debug Fenster dazu?

    Setze doch einfach einen Breakpoint auf PostNcDestroy und debugge...

    BTW: Man kann auch eine dialog basierende Anwendung anders bauen.
    http://blog.m-ri.de/index.php/2008/09/14/dialog-basierende-mfc-anwendungen-einmal-anders/


    Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
    Donnerstag, 12. Mai 2011 08:36
    Moderator
  • Hallo Martin

    Ich mache definitiv keinen exit() und werfe auch keine Exceptions oder mache sonst irgendwas, das diesbezueglich verdaechtig waere. Das Programm ist natuerlich nicht mehr ganz schlank und kommuniziert ueber TCP/IP mit einem Server und macht allerlei andere Dinge.

    Zu eurem Trost kann ich nur sagen, dass ich jetzt ein voellig neues Testprogramm erstellt habe, auch einen einfachen Thread gestartet und alles so gemacht, wie in meiner urspruenglichen Anfrage beschrieben...und natuerlich habe ich NICHT Recht. Das einfache Testprogramm verhaelt sich so, wie man es erwarten wuerde. Ich habe keine Ahnung, warum das "grosse" Programm sich anders verhaelt. Normalerweise sollten bei solchen Anomalien die Alarmglocken laeuten, nur weiss ich nicht, wo ich zu suchen beginnen soll, zumal das Programm tagelang einwandfrei gelaufen ist und auch sonst keine Probleme macht.

    Das Verhalten ist auf jeden Fall aeusserst interessant und ich konnte es mit einem Work-Around auch in den Griff bekommen; mal sehen, welche Phaenomene noch auftauchen.

    Am Ende werde ich vermutlich wieder einmal vor dem allbekannten Programmiererproblem stehen:
    Hilfe, mein Computer macht, was ich ihm befehle und nicht was ich will

    Gruesse

    FireHeart

    Donnerstag, 12. Mai 2011 08:57
  • Setze doch einfach einen Breakpoint auf "ExitProcess"!


    Jochen Kalmbach (MVP VC++)
    Donnerstag, 12. Mai 2011 09:04