AfxMessageBox wird nach Ausführung eines anderen Threads nicht angezeigt



  • Hallo,

    ich habe seit Jahren eine Klasse CStatusDialog, die aber selbst kein Dialog ist, sondern deren Konstruktor mit AfxBeginThread einen 2.Thread startet und in diesem Thread einen Dialog anzeigt, so dass der User bei länger laufenden Dingen den Fortschritt in diesem zweiten Dialog angezeigt bekommen kann.
    Bei Aufruf der Member CStatusDialog::CloseDialog im 1.Thread wird dann der im 2.Thread laufende Dialog wieder geschlossen und dabei auch der 2.Thread mit
    PostQuitMessage(0);
    beendet.
    Das hat so jahrelang scheinbar problemlos funktioniert; jedenfalls waren keine Probleme damit feststellbar.
    (Die Kommunikation von CStatusDialog mit dem 2.Thread läuft übrigens über Member-Variablen)

    Nun habe ich aber eine Source-Stelle, wo zuerst ein CStatusDialog angezeigt und dann etwas später mit CloseDialog wieder geschlossen wird, und ziemlich unmittelbar danach soll eine AfxMessageBox angezeigt werden.

    Das Problem dabei ist, dass dort die AfxMessageBox meistens(!) nicht angezeigt wird, sondern sofort den Wert 0 zurückgibt (auch die letztlich in AfxMessageBox aufgerufene Win-API-Funktion "MessageBox" gibt 0 zurück).
    Für den Rückgabewert 0 konnte ich (zB. in https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx) aber keine Doku finden.
    Das Problem tritt nur meistens(!) auf, sporadisch tritt es nicht auf, sondern die MessageBox wird dann korrekt angezeigt.

    Wenn ich nun Aufruf und Schließen von CStatusDialog im Source auskommentiere, dann wird die AfxMessageBox immer korrekt angezeigt.
    Die vorangehende Verwendung von CStatusDialog scheint hier also die MessageBox-Anzeige irgendwie zu verhindern.

    Ich hatte die Vermutung, dass da der 2.Thread aus irgendwelchen Gründen nicht korrekt beendet wird und dann irgendwie "stört".
    Deshalb habe ich in den aufrufenden Source im 1.Thread hinter CStatusDialog::CloseDialog und vor die MessageBox mal ein
    ::WaitForSingleObject(m_pThread->m_hThread, INFINITE)
    gesetzt (m_pThread ist der Pointer auf den 2.Thread), und dann hängt das Programm auch tatsächlich an dieser Stelle.

    Ich habe nun schon etliche Stunden damit verbracht und so langsam gehen mir die Ansatzpunkte aus; deshalb:

    Hat jemand eine Idee woran das liegt und wo ich weitersuchen muss, um die Ursache und ggf. Lösung zu finden ?
    Oder kennt jemand das Problem und weiss Ursache oder gar Lösung dafür ?

    Bin für jeden Hinweis dankbar.

    Gruss

    Werner


  • Mod

    Ich gehe davon aus, dass die MessageBox auch in dem 2. Thread liegt, der durch PostQuitMessage beendet wird.

    Und genau hier liegt das Problem. Wenn PostQuitMessage gesendet wird oder gesendet wurde wird keine MessageBox mehr in diesem Thread angezeigt.

    Siehe auch:
    http://blogs.msdn.com/b/oldnewthing/archive/2005/11/04/489028.aspx
    http://blogs.msdn.com/b/oldnewthing/archive/2005/02/22/378018.aspx

    Beachte den zweiten Artikel und wenn Dir klar ist, dass eine MessageBox ein modaler Dialog ist, dann ist auch klar warum es nicht geht.



  • Martin Richter schrieb:

    Ich gehe davon aus, dass die MessageBox auch in dem 2. Thread liegt, der durch PostQuitMessage beendet wird.

    Nein, das ist nicht der Fall: der AfxMessageBox-Aufruf steht im 1. Thread direkt nach dem Aufruf der Member CloseDialog, die (über Setzen einer bool'schen Variable) im 2. Thread zuerst DestroyWindow für den Dialog und dann PostQuitMessage(0) aufruft.

    Debugging, weitere Recherche und Rumprobieren haben inzwischen noch ergeben:

    Wenn ich statt AfxMessageBox die Funktion
    ::MessageBox(AfxGetMainWnd()->m_hWnd,..)
    verwende, funktioniert diese immer korrekt;
    es ist also ein Problem von AfxMessageBox, nicht von ::MessageBox

    Wenn ich direkt nach ::MessageBox zusätzlich testweise auch AfxMessageBox aufrufe, dann funktioniert diese auch (wieder).

    AfxMessageBox ermittelt das hWnd ja selber.
    In einem Deiner Blog-Einträge http://blog.m-ri.de/index.php/2009/12/03/afxmessagebox-versus-cwndmessagebox/ , den ich bei der Recherche gefunden habe, schreibst du ja, man solle immer
    AfxMessageBox (statt CWnd::MessageBox) verwenden, wobei in diesem Zusammenhang va. Punkt 3. von Belang ist.

    Es scheint aber so, als ob AfxMessageBox in meinem og. Fall ein "falsches" hWnd ermittelt und daraus dann das Problem entsteht.
    (hWnd wird in appui1.cpp in CWinApp::ShowAppMessageBox mit HWND hWnd = CWnd::GetSafeOwner_(NULL, &hWndTop); ermittelt)

    Bei meinen Recherchen bin ich auf http://forums.codeguru.com/showthread.php?162419-AfxMessageBox-returns-0-symptom-of
    gestossen und habe mal (obwohl dort andere Anfangsvoraussetzungen vorliegen) den dortigen Workaround probiert, und tatsächlich löst der auch mein Problem;
    aber es ist unklar, wieso ein Aufruf von :
    ::SetWindowPos(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    (im 1. Thread nach dem Schließen des Windows des 2. Threads) dazu führt, dass danach AfxMessageBox wieder das richtige hWnd findet.

    Deshalb habe ich etwas Bauchschmerzen damit, es dabei zu belassen und würde das Problem lieber an der Wurzel lösen als mit diesem Workaround.

    Was könnte die Ursache dafür sein ?



  • Der in 4. erwähnte SetWindowPos-Aufruf entspricht ja:
    ::SetWindowPos(AfxGetApp()->m_pMainWnd->GetSafeHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    bringt also das Main-Wnd der Applikation (=des 1. Threads) wieder "at the top of the Z order", und dann wird es von AfxMessageBox bzw. CWnd::GetSafeOwner_ anscheinend auch wieder korrekt gefunden.
    Es ist zwar schon so, dass das vom 2.Thread angezeigte Status-Window oberhalb des Main-Wnd angezeigt wurde; aber zum einen ist das ja zu diesem Zeitpunkt schon wieder destroyed und zum anderen ist für mich weiterhin unklar, wieso das MainWnd für erfolgreiches AfxMessageBox überhaupt on top of Z order sein muss.


  • Mod

    Weil sonst das falsche Fenster disabled wird.


Log in to reply