PostMessage() nach DestroyWindow(): Undefiniertes Verhalten?
-
Hey!
Ich würde gerne wissen, ob es problematisch ist, PostMessage() für ein Fenster-Handle aufzurufen, für welches bereits DestroyWindow() aufgerufen wurde.
Das ist auch schon alles, danke!
MfG
-
Vergessen zu erwähnen: Die message loop könnte dabei auch schon beendet sein. Das macht mir halt Sorgen.
-
Achja, und noch was:
Wüsste das auch gerne für Childs, ob es da Probleme geben kann.
Wenn also das Fenster schon zu ist, message loop beendet oder auch nicht, ob dann ein Send/PostMessage() zu Childs Probleme macht (WM_CLOSE, WM_SETTEXT, PBM_SETPOS usw...).
-
Ach verdammt, WM_CLOSE natürlich nicht zu Childs aber zum Hauptfenster zB.
-
DestroyWindow() zerstört ein Fenster.
Danach isses "weg".
Das HWND wird dadurch auch ungültig.
Daher darfst du auch keine Messages mehr hinschicken.Sollte doch wohl irgendwie klar sein

-
Bevor Du PostMessage ausführstkannst Du doch prüen ob das Fenster-Handle noch gültig ist. (IsWindow)
Wenn die Nachricht in der Queue ist spielt es keine Rolle.Wie kommst Du denn überhaupt zu so einem eigentümlichen Konstrukt?
Wenn die Messagellop beendet ist, dann spielt es soweiso keine Rolle mehr, denn dann wird die Nachricht nicht ausgeliefert.
Aber wieso kann die Messageloop beendet werden, wenn noch Fenster existieren. PostQuitMessage löst man erst aus, wenn WM_DESTROY im Main Fenster ankommt.
-
@hustbaer
Ja, und wenn ich es doch tue? UB? Oder wird es intern einfach ignoriert?@Martin
Ich habe zwei Threads. Der Mainthread mit der message loop, und ein weiterer Thread, welcher eine Datei herunterlädt.
Schließt man jetzt während des Downloads das Fenster, wartet der Mainthread nach der message loop mit WaitForSingleObject() auf den Downloadthread. Dieser könnte dann noch SendMessage() aufrufen, weil er nämlich während des Downloads ein paar Controls verändert (Progress Bar, ...).
Der Download wrid zwar abgebrochen, aber der Downloadthread ruft dann noch SendMessage() mit WM_CLOSE auf, unabhängig davon, ob das Fenster jetzt schon vom User geschlossen wurde (Nach dem Download soll das Fenster auch geschlossen werden).Also muss ich eine extra Abfrage einbauen (IsWindow()), oder ist es egal, wenn ich zu nicht mehr existierenden Fenstern Nachrichten schicke? Probleme gab es bis jetzt jedenfalls keine.
MfG
-
1. Warum nutzt Du überhaupt SendMessage?
2. Könntest Du einfach bevor das Fenster geschlossen wird, dem Thread sagen das fini ist. Der Thread weiß dann, nun ist Schluß und er darf nix mehr senden und wird alsbald terminieren.
Dann blockiert auch nichts.
-
Weil ich mit SendMessage() vom Downloadthread das Fenster+Childs vom Hauptthread erreichen will.
Ja, es wird auch "abort = true;" gesetzt. Aber dann lauter Abfragen im Downloadthread "if(abort) ..." finde ich unschön.
-
1. Kannst Du eine Funktion in der Threadklasse schreiben, die NotifyThread heißt und dann hast Du nur eine Stelle mit SendMessage. Ich finde verteile SendMessage aufrufe in einem Thread unschön, schon ganz und gar wenn mehrere Fenster bedient werden...
2. Warum sendest Du nicht nur eine einzige Nachricht immer an das Hauptfenster und diese Nachricht wird dann an die Unterfenster verteilt.
3. Durch SendMessage erreicht man eine threadsynchronisation, warum also nicht PostMessage?
-
Also NotifyThread() soll ein PostMessage() mit IsWindow() Abfrage davor sein?
Wie, nur eine Nachricht? Es werden Nachrichten von verschiedenen Stellen gesendet.
Im Downloadthread, wenn ein URLDownloadToFile() fehlschlägt, werden Childs aktualisiert (static control: "Download failed").
Im Downloadthread, in IBindStatusCallback::OnProgress() wird eine Progress Bar upgedated.Ich gehe außerdem nicht davon aus, dass die message loop hängen bleibt, also brauche ich doch kein PostMessage()?
-
Für die Kommunikation eines Threads mit einem Fenster, sende ich nur eine Nachrichtenart (WM_APP+n), in den Argumenten w/lParam, sage gebe ich an was passiert.
Das Mainwindow ist verantwortlich für den Progressbar etc...
Apropos MessageLoop: Du hast doch genau jetzt das Problem. Deine Messageloop hört auf zu laufen und SendMessage blockiert

-
Ok und was ist der Vorteil, nur eine Nachricht zu senden?
Und ich habe es mehrfach getestet, SendMessage() blockiert nicht, wenn die message loop schon beendet ist.
-
Destroy0r schrieb:
Ok und was ist der Vorteil, nur eine Nachricht zu senden?
Und ich habe es mehrfach getestet, SendMessage() blockiert nicht, wenn die message loop schon beendet ist.
Aber nur wenn das Fenster nicht mehr existent ist!
Sonst muss es blockieren...
-
Naja, dass das Fenster noch existiert während die message loop schon beendet ist, kommt in meiner Anwendung nie vor. Oder wie könnte es dazu kommen?
WM_CLOSE -> DestroyWindow()
WM_DESTROY -> PostQuitMessage()Und wenn ich ja mit IsWindow() prüfen kann, sehe ich keinen Vorteil in einer einzigen WM_APP+n Nachricht. Dann müsste ich dafür außerdem eventuell noch extra Strukturen definieren...
Oder findest du es einfach schöner, wenn ein Thread nur an das Hauptfenster, nicht aber an die Childs sendet?
-
@hustbaer
Ja, und wenn ich es doch tue? UB? Oder wird es intern einfach ignoriert?Wieso interessiert dich das? Schreib dein Programm so, dass der Fall nicht vorkommt.
@Martin:
IsWindow() ist sinnlos, dann kann er genauso gleich die Message absetzen. Wenn das Handle nicht schon neu vergeben wurde, dann geht die Message ins nirvana, und es passiert einfach nix. Bzw. wird die Message nichtmal abgeschickt.
Und WENN das Handle schon neu vergeben wurde, dann wird IsWindow() auch true melden, obwohl es schon ein ganz anderes Fenster gibt.IsWindow() ist IMO nur für ASSERTs brauchbar.
-
Weil ich dann im Downloadthread ne zusätzliche Abfrage brauche. Und da ich jetzt IsWindow() nicht verwenden soll, wohl irgendwie so:
bool _abort; EnterCriticalSection(&criticalSectionAbort); _abort = abort; LeaveCriticalSection(&criticalSectionAbort); if(!_abort) PostMessage(dialogHandle, WM_CLOSE, 0, 0);Aber gibt es nun kein UB?
-
@Destroy0r: Deine CriticalSection ist absolut unnötig.
Bei Deinem Konstrukt stellt sich für mich einfach die Frage,warum ein zerstören des Hauptfensters überhaupt erlaubt ist, während der Download läuft.@hustbaer: Window Handles werden nicht "schnell" recycled. Das ist so weit erstmal sicher. Es gibt aber genug Race-Konditions in denen man z.B. in PreTranslateMessage, oder einem Hook etwas auslöst, was zum Beispiel andere Fenster zerstört. In diesem Moment kommt IsWindow schon zum tragen.
Was SendMessage angeht, gebe ich Dir recht, allerdings gibt IMHO im Aplication Verifier einen Break, wenn ein Handle verwendet wird, das nciht existiert!
Durch ein Certified for xyz würde die Anwendung dann durchfallen.
-
Ne, die ist nicht unnötig, weil "abort" im Hauptthread auf "true" gesetzt wird, und zwar bevor dort DestroyWindow() aufgerufen wird.
Und sobald eine Variable in zwei Threads verwendet wird, muss doch synchronisiert werden.Und ich möchte dem User die Kontrolle lassen, wann er den Updater abbrechen will. Wenn ein Download läuft, muss der User bestimmt nicht warten, bis dieser fertig ist.
Er wird dann zwar durch IBinding::Abort() abgebrochen, aber es könnte Folgendes passieren:if(!abort) { UrlDownloadToFile(... ...Wenn abort noch false ist, und genau danach das Fenster geschlossen wird, während also erstmal UrlDownloadToFile() beginnt, darf man noch nicht IBinding::Abort() aufrufen.
Und wenn der Server dann hängt, hängt die Applikation.Deshalb werde ich wohl libcurl mit dem multiinterface verwenden, da kann immer kontrolliert abgebrochen werden.
-
Destroy0r schrieb:
Ne, die ist nicht unnötig, weil "abort" im Hauptthread auf "true" gesetzt wird, und zwar bevor dort DestroyWindow() aufgerufen wird.
Und sobald eine Variable in zwei Threads verwendet wird, muss doch synchronisiert werden.nö es ist eine atomare operation
-
@hustbaer: Window Handles werden nicht "schnell" recycled.
Das weiss ich schon.
Das ist so weit erstmal sicher.
Sicher nenne ich was anderes. Sagen wir lieber es macht die Sache weniger schlimm.
Es gibt aber genug Race-Konditions in denen man z.B. in PreTranslateMessage, oder einem Hook etwas auslöst, was zum Beispiel andere Fenster zerstört. In diesem Moment kommt IsWindow schon zum tragen.
Jo. Deswegen ist IMO das ganze Window-Gedöns in Windows ja auch ein riesen Haufen Müll.
Was SendMessage angeht, gebe ich Dir recht, allerdings gibt IMHO im Aplication Verifier einen Break, wenn ein Handle verwendet wird, das nciht existiert!
Durch ein Certified for xyz würde die Anwendung dann durchfallen.Mag sein, ich hab noch nie eine Anwendung verifizieren lassen. Ist aber total bescheuert, weil wie gesagt das nötige "if" ja schon in SendMessage steckt.