Mehrfaches Öffnen von MessageBox verhindern.



  • ups.. vergessen...
    Die MessageBox bilde ich so:

    if ((CommandComplete[3] == 0x02) && (readnak[0] == 0x05))
    {
    	memcpy(readnak, Buffer0, 10);
    	memcpy(CommandComplete, Buffer0, 11);
    	MessageBox("Befehl wurde nicht gesendet", "Warnung!");
    	//ToDo: Verhindern, dass die Warnung mehrfach geöffnet wird!
    	return false;
    }
    

    CommandComplete steckt der komplette gesendete Befehl.
    In readnak wird die Antwort der Karte geschrieben.

    PS: Gibt es eine Möglichkeit den OK Button der MessageBox abzufragen, bzw. da Code
    reinzupacken, so dass ich eine Bool Variable auf FALSE setzen könnte?



  • Mackie1980 schrieb:

    PS: Gibt es eine Möglichkeit den OK Button der MessageBox abzufragen, bzw. da Code
    reinzupacken, so dass ich eine Bool Variable auf FALSE setzen könnte?

    Also, bei AfxMessageBox geht das ganz einfach - ich vermute, bei MessageBox ist es nicht anders:

    if (IDOK == AfxMessageBox("Bla"))
    {
    // Ok wurde gedrückt
    }
    

    Aber normalerweise kommt keine Box mehrfach (ist modal), es sei denn, du arbeitest mit Threads. 😕



  • Wie estartu schon sagte - die MessageBox ist modal, d.h. die Funktion wartet normalerweise, bis du einen Button gedrückt hast.



  • ohh.. das ist jetzt aber sehr merkwürdig...

    Also bei MessageBox("bla..") öffnen sich beliebig viele Fenster.
    Bekomme auch für jedes Fenster in der Taskleiste einen Eintrag angezeit.

    Bei AfxMessageBox("bla..") bekomme ich zwar logischerweise keinen Eintrag in der Taskleiste, aber es liegen beliebig viele Fenster übereinander, die ich alle mit OK bestätigen muss.
    hmm...
    aber das mit der If Abfrage müsste doch irgendwie zu machen sein.
    Ich dachte ich mache ne BoolVariable die mir angibt ob das Fenster geöffnet oder geschlossen ist. Beim Start ist:

    MessageCommError = false;
    

    Kommt ein NAK muss MessageCommError auf true gesetzt werden.
    So und da hört meine Idee auf:

    if ((CommandComplete[2] == 0x09) && (readnak[0] == 0x05)) // Das ist ein NAK.
    {
    	MessageCommError = true;
    	if (MessageCommError == true)
    	{
    		if (IDOK == AfxMessageBox("Befehl wurde nicht gesendet"))
    		{
    			MessageCommError = false;
    		}
    	}
    

    Der Code macht natürlich wenig Sinn. Das Fenster wird jetzt jedesmal geöffnet.
    Wie kann ich das verhindern? Reicht mir da die BoolVariable?



  • Arbeitest du mit Threads? Wenn du für jede Nachricht einen eigenen Thread startest, ist das Verhalten nachvollziehbar (der Thread, der gerade die MB gestartet hat, wartet, aber alle anderen laufen unbeirrt weiter). Da ist es eventuell hilfreicher, die Nachrichten nacheinander im selben Thread zu starten (d.h. die nächste Nachricht wird erst gesendet, wenn die vorige korrekt durchgekommen ist).

    Ansonsten: Ja, normalerweise reicht eine bool-Variable, die aber global erreichbar sein muß - die Anwendung mußt du aber nochmal überdenken:

    if(...)
    {
      if(!MessageCommError)
      {
        MessageCommError=true;
        MessageBox(...);
        MessageCommError=false;
      }
    }
    

    (wobei du da sowieso Mutex als Sperre verwenden solltest, um den Zugriff zu synchronisieren - und dann kann dieser Mutex gleich selbst als "MB ist aktiv"-Marke genutzt werden)



  • hmm... peinlich peinlich.. ich weiss nicht genau was ein Thread bzw. Mutex ist. 😕
    Nach etwas googlen glaube ich allerdings nicht, dass ich damit arbeite, zumindest nicht bewusst.
    Ich probiere mich weiter an der BoolVariable Variante aber welche Infos braucht ihr, um mir evtl. doch weiterhelfen zu können?
    Grober Aufbau des Programms?
    Danke für bisherige Infos.



  • probier dies (ungetestet):

    int SingleMessageBox (HWND h, LPCTSTR text, LPCTSTR capt, UINT type)
    {
        static volatile LONG lock;
        volatile int res;
        if (InterlockedIncrement(&lock) == 1)
            res = MessageBox (h, text, capt, type);
        else
            res = -1; // irgendein wert, der bedeutet, dass keine msgbox erzeugt wurde
        InterlockedDecrement (&lock);
        return res;
    }
    

    🙂



  • @CStoll: Du Tier. So läufts natürlich! Vielen Dank!!
    Aber warum soll ich Mutex verwenden und keine BoolVariable?

    @Undertaker: Code wird getestet. Vielen Dank!

    Einfach ein Top-Forum!



  • Mackie1980 schrieb:

    hmm... peinlich peinlich.. ich weiss nicht genau was ein Thread bzw. Mutex ist. 😕
    Nach etwas googlen glaube ich allerdings nicht, dass ich damit arbeite, zumindest nicht bewusst.

    Wenn du nicht weißt, was du machst, hast du ein Problem 😃 Wie genau sieht denn deine gesamte Nachrichtenverarbeitung aus?

    Zur Erklärung: MessageBox() blockiert normalerweise den Thread, von dem aus es aufgerufen wurde, bis du die MB wieder geschlossen hast. Deshalb können die weiteren auftauchenden MB's nur aus anderen Threads kommen.

    Mackie1980 schrieb:

    @CStoll: Du Tier. So läufts natürlich! Vielen Dank!!
    Aber warum soll ich Mutex verwenden und keine BoolVariable?

    Die einzelnen Threads müssen natürlich sich gegenseitig synchronisieren, um nicht durcheinanderzukommen (es darf immer nur ein Thread gleichzeitig auf die Variable zugreifen - und natürlich sollte zwischen dem if() und der anschließenden Zuweisung auch niemand dazwischenfunken), also brauchen sie einen Mutex, um den Zugriff zu regeln. Und damit hast du den Mutex, der deine bool-Variable sichert, die wiederum die MessageBox()-Aufrufe steuert - da ersparen wir uns doch die Variable und sichern mit dem Mutex direkt die MessageBox.



  • CStoll schrieb:

    Zur Erklärung: MessageBox() blockiert normalerweise den Thread, von dem aus es aufgerufen wurde, bis du die MB wieder geschlossen hast. Deshalb können die weiteren auftauchenden MB's nur aus anderen Threads kommen.

    ich glaube bei WM_TIMER messages kann das auch passieren (vielleicht wenn HWND 0 ist, oder so)...
    🙂



  • Nein, bei normalen Nachrichten kann das nicht passieren - die Windows Nachrichtenbehandlung ist sequentiell, d.h. erst wenn eine Nachricht fertig ist, wird die nächste angestoßen (und WM_TIMER wird nichtmal durchgelassen, wenn noch andere Nachrichten warten).



  • CStoll schrieb:

    Nein, bei normalen Nachrichten kann das nicht passieren - die Windows Nachrichtenbehandlung ist sequentiell, d.h. erst wenn eine Nachricht fertig ist, wird die nächste angestoßen (und WM_TIMER wird nichtmal durchgelassen, wenn noch andere Nachrichten warten).

    sollte eigentlich so sein, ist aber nicht so. 😉
    ich hab's gerade ausprobiert, ein mfc-dialogbasiertes programm, in die OnInitDialog ein: SetTimer (1, 1000, 0); und den timer-handler so:

    void CTimertestDlg::OnTimer(UINT nIDEvent) 
    {
        ::MessageBox (0, "hallo", "doof", MB_OK);
    	CDialog::OnTimer(nIDEvent);
    }
    

    das gibt jede sekunde eine neue msgbox, die liegen zwar übereinander, aber wenn du sie verschiebst, siehst du die anderen.
    🙂



  • Wenn man sich auf einen Thread beschränkt braucht man garkeine Synchronisierung.
    Wenn man mehrere Threads verwendet wäre es IMO besser eine Thread-Lokale Variable zu verwenden.



  • hustbaer schrieb:

    Wenn man mehrere Threads verwendet wäre es IMO besser eine Thread-Lokale Variable zu verwenden.

    Und was nützt eine thread-lokale Variable, wenn man Probleme mit der Zusammenarbeit mehrerer Threads hat 😉



  • CStoll schrieb:

    hustbaer schrieb:

    Wenn man mehrere Threads verwendet wäre es IMO besser eine Thread-Lokale Variable zu verwenden.

    Und was nützt eine thread-lokale Variable, wenn man Probleme mit der Zusammenarbeit mehrerer Threads hat 😉

    ???
    Eine thread-lokale Variable ganz einfach deswegen, damit nicht ein Thread eine Message-Box eines anderen Threads blockiert. Die könnte aus einem ganz anderen Grund angezeigt werden - wäre IMO nicht gut die dem User einfach vorzuenthalten.

    Und: für den Zugriff auf eine thread-lokale Variable muss man eben nix synchronisieren, da jeder Thread hübsch seine eigene Kopie bekommt.



  • CStoll schrieb:

    Nein, bei normalen Nachrichten kann das nicht passieren - die Windows Nachrichtenbehandlung ist sequentiell, d.h. erst wenn eine Nachricht fertig ist, wird die nächste angestoßen (und WM_TIMER wird nichtmal durchgelassen, wenn noch andere Nachrichten warten).

    Das ist nicht richtig.
    Probier es aus, Code der das entsprechende Verhalten zeigt wurde gepostet.
    Der Knackpunkt hierbei ist dass es unter Windows kein "haben fertig bearbeitet" gibt für eine Message, d.h. Windows kann garnicht wissen wann eine WM_XYZ fertig abgearbeitet ist. Daher werden auch feste neue WM_TIMER (oder sonstwas) gepostet wenn keine NEUEN Nachrichten mehr in der Queue stehen, obwohl die zuletzt abgeholte noch nichtmal fertig abgearbeitet wurde.



  • @WM_TIMER: OK, ihr habt mich überzeugt. Aber ich war bisher davon ausgegangen, daß es im Programm eine zentrale Nachrichtenschleife gibt, die nacheinander Nachrichten entgegennimmt und die dazugehörigen Handler aufruft (und dann wartet, bis der Handler fertig ist, bevor sie weitermacht).

    @Synchronisation: Nein, mit dem Ansatz sollten nicht alle irgendwo entstehenden MessageBoxen blockiert werden, sondern nur "meine" (bzw. die MB's, die dem Anwender mitteilen wollen, daß das Senden schiefgegangen ist) - und die können durchaus thread-übergreifend auftreten.
    (aber Mackie hat uns ja immer noch nicht verraten, wie sein Programm zusammenarbeitet - also ist alles weitere reine Spekulation)


Anmelden zum Antworten