LB_GETCOUNT reagiert wie ein blocking call...
-
Naja, nach dem Beenden des Programms ist auch die Nachrichtenschleife futsch.
Der thread, welcher SendMessage() aufruft, läuft dann aber meist noch einmal durch, bevor er eben wieder zur Abfrage des Abbruchkriteriums gelangt...Wenn ich...
if(FindWindowEx(listHandle, 0, 0, 0)) SendMessage(listHandle, LB_GETCOUNT, 0, 0);...schreibe, dann wird brav geschlossen. Also liegt es wohl, wie du schon vermutet hast, daran, dass SendMessage() noch aufgerufen wird, obwohl das Hauptfenster (Und somit der MsgProc()?) schon futsch ist...
Mit PostMessage() schließt der Thread nun, aber der aufrufende thread hat nicht die Nachrichtenschleife. Da wollte ich PostThreadMessage() verwenden, aber wie bekomme ich die ID des Hauptthreads, der bei jedem Programm existiert, ohne dass man ihn erstellen muss, und ist das überhaupt der richtige Weg so?
Danke!
MfG
-
Oh sry, das hab ich überlesen:
"The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window "
Naja weil mit PostMessage() erhalte ich nicht mehr die Ergebnisse als wie mit SendMessage(). LB_GETCOUNT ist immer 1 und LB_ADDSTRING hat auch keinen Effekt mehr...
Die Nachrichtenschleife des parent windows sieht übrigens so aus:
MSG message = { }; while(GetMessage(&message, 0, 0, 0)) { if(!IsDialogMessage(MyClass::getInstance().getWindowHandle(), &message)) { TranslateMessage(&message); DispatchMessage(&message); } }Nochmal, vielleicht zur Entwirrung:
PostMessage() sende ich von einem zweiten Thread aus, hat aber keinen Effekt auf die ListBox... SendMessage() schon.Danke!
MfG
-
Wo wird denn exitMainThread gesetzt? Ist die Variable global, setzte sie doch in der Messageloop an die du die Sendmessage schickst.
-
Ok, kurz und bündig:
Hauptthread:
- Parent window mit MsgProc
- Child window (listHandle)
Bei WM_DESTROY wird exitMainThread auf true gesetztNebenthread:
while(!exitMainThread) { Tick(); }Nachdem man das Programm beendet, werden ja die Fenster abgebaut, und der MsgProc wird dann auch nicht mehr aufgerufen. Aber der Nebenthread macht noch einen Durchgang mit SendMessage(listHandle, ...), wo er dann stecken bleibt, weil wohl das Child schon abgebaut ist bzw. der MsgProc nicht mehr vorhanden ist.
PostMessage hat keinen Effekt, SendNotifyMessage oder SendMessageCallback hab ich auch schon probiert, hat alles keinen Effekt, nur SendMessage tut was, blockiert aber leider...
Danke!
MfG
-
Fenster sind und bleiben threadafin. Deshalb sollten Threads mit anderen Fenstern aus anderen Threads nihths zu tun haben.
Man sollte SendMessage nur verwenden, wenn man eine Threadsynchronisation will!
PostMesssage ist nett birgt aber auch die Gefahr, die Messagequeue zuzuballern wenn der Hauptthread keine Nachrichten abholen kann (was man natürlich vermeiden sollte). Erste Wahl bleiben immer noch Events/Mutexe/Semaphoren...Grundsätzlich ist es mieses Design, Deinen Hauptthtead beenden zu lassen (Fenster die andre verwenden zu zerstören), ohne die Workerthreads kontrolliert zu terminieren.
-
Martin Richter schrieb:
Grundsätzlich ist es mieses Design, Deinen Hauptthtead beenden zu lassen (Fenster die andre verwenden zu zerstören), ohne die Workerthreads kontrolliert zu terminieren.
ACK
-
Ok, aber was soll ich nun tun?
Ich brauche ja neben dem Hauptthread noch einen weiteren, damit wenn mein Programm was tut, das GUI nicht ausgebremst wird.
Soll ich beim beenden einfach TerminateThread aufrufen? Gibt ja keinen Speicher frei usw...Danke!
MfG
-
Blos nicht - die bessere Lösung ist es, über Events oder ähnliches den Threads zu sagen, daß sie ihre Arbeit beenden sollen, und dann mit WaitForMultipleObjects() darauf warten, daß alle fertig sind.
(TerminateThread ist eine Notfalllösung für den Fall, daß der Thread dir dein Betriebssystem zerhackstückt)
-
Aber wie können die ihre Arbeit beenden, ohne ein Abbruchkriterium in einer Schleife? Denn es muss ja verhindert werden, dass wenn das Programm schließt, der Nebenthread noch einmal durchläuft. Oder muss ich vor jedem SendMessage() FindWindowEx() aufrufen (Wäre ja auch nicht 100% sicher!?) ?
MfG
-
Indem du ihnen ein Abbruchkriterium gibst (gut macht sich da "WaitForSingleObject(endeEvent,0)==WAIT_TIMEOUT"). Die Nachrichtenschleife lebt durch den Wait...() Aufruf im Hauptprogramm noch lange genug, auch wenn die Nachrichten eventuell nicht mehr ausgewertet werden.
Aber der Nebenthread sollte dann statt SendMessage() lieber PostMessage() oder SendMessageTimeout() verwenden, um das Hauptprogramm über Neuigkeiten zu informieren, sonst bekommst du einen erstklassischen Deadlock (der Thread wartet darauf, daß das Hauptprogramm seine Nachricht verarbeitet, das Hauptprogramm wartet darauf, daß der Thread sich beendet).
-
Hey!
Mit...
SendMessageTimeout(listHandle, LB_ADDSTRING, 32, reinterpret_cast<LPARAM>("blatext"), SMTO_ABORTIFHUNG, 1, 0)...haut es nun hin. Die Reaktion auf WM_DESTROY sah schon immer so aus:
if(threadHandle) WaitForSingleObject(threadHandle, INFINITE); CloseHandle(threadHandle); PostQuitMessage(0);Eigentlich sollte hier doch sowieso gewartet werden, bis der Nebenthread fertig ist, und dann erst die Nachrichtenschleife & Fenster zerstört werden?!
Danke!
MfG
-
ceplusplus@loggedoff schrieb:
Hey!
Mit...
SendMessageTimeout(listHandle, LB_ADDSTRING, 32, reinterpret_cast<LPARAM>("blatext"), SMTO_ABORTIFHUNG, 1, 0)...haut es nun hin.
Meinst du nicht, daß ein Timeout von einer Millisekunde im aktiven Dienst ein wenig knapp bemessen ist? Wenn du Pech hast, kommt die Nachricht gerade während einer etwas längerfristigen Tätigkeit des Hauptprogramms.
Eigentlich sollte hier doch sowieso gewartet werden, bis der Nebenthread fertig ist, und dann erst die Nachrichtenschleife & Fenster zerstört werden?!
Ja, das war auch korrekt - nur während du dort gewartet hast, blieben die Nachrichten des Thread in der Warteschlange hängen.
-
Oh, hmm stimmt! Also bin ich gezwungen, ein Timeout zu setzen?
SendMessageTimeout() funktioniert leider doch nicht wie gewollt:SendMessageTimeout(listHandle, LB_GETCOUNT, 0, 0, SMTO_ABORTIFHUNG, 1000, 0);Gibt immer 1 zurück, SendMessage() hingegen arbeitet korrekt. Warum hat PostMessage() usw. eigentlich keinen Effekt bei mir (Gibt bei LB_GETCOUNT auch immer 1 zurück und LB_ADDSTRING zB. hat gar keinen Effekt) ?
Danke!
MfG
-
Die Rückgabewerte von PostMessage() und SendMessageTimeout() sind nicht die Daten, die die Behandlungsfunktion geliefert hat. Bei PostMessage() kannst du keine Rückmeldung bekommen, weil die Nachricht ja noch unterwegs sein dürfte. Bei SendMessageTimeout kannst du als letzten Parameter eine DWORD-Variable, wo die Antwort im Erfolgsfall reingeschrieben wird:
DWORD answer,result; result = SendMessageTimeout(listHandle,LB_GETCOUNT,0,0,SMTO_ABORTIFHUNG,1000,&answer); if(result==0) { //Fehler oder Timeout } else { //Erfolg: TRACE("Count returned: %d\n",answer); }(PostMessage() mit LB_ADDSTRING hat ein anderes Problem - der übergebene String ist möglicherweise schon ungültig, bevor das Zielfenster die Nachricht auswertet)
-
Hey!
Danke, meine Voreiligkeit

Hätte es gerne irgendwie ohne Timeout gelöst, also falls wem noch was einfällt, bitte!
MfG
-
Es gibt auch noch SendMessageNotify() und SendMessageCallback() als Alternativen (die aber beide nicht mit Zeigern umgehen können - das selbe Problem wie bei PostMessage()).
Aber was genau hast du eigentlich gegen Timeout? Die Angabe dort bedeutet doch nicht, daß die Funktion immer 1 Sekunde wartet, bevor sie abbricht - das ist die maximale Wartezeit. (und im Normalbetrieb liefert sie genauso zuverlässig eine Antwort wie SendMessage())
-
Naja, die Anwendung läuft dann eben nach Beenden noch eine Zeit lang weiter, wenn ich im Nebenthread oft SendMessageTimeout() aufrufe, kommen schon mal 10 Sekunden oder mehr zusammen. Find ich nicht so toll.
Was meinst du mit "kann nicht mit Zeigern umgehen"? Dass ich zB. nicht LB_GETCOUNT verwenden kann? Denn wenn diese Funktionen sofort zurückkehren, und die Nachricht noch nicht verarbeitet wurde, wo soll dann das Ergebnis sein?
MfG
-
ceplusplus@loggedoff schrieb:
Naja, die Anwendung läuft dann eben nach Beenden noch eine Zeit lang weiter, wenn ich im Nebenthread oft SendMessageTimeout() aufrufe, kommen schon mal 10 Sekunden oder mehr zusammen. Find ich nicht so toll.
Da wäre es auch eine gute Idee, die Bedingung "Timeout wurde ausgelöst" als Abbruchbedingung des Threads zu verwenden - so daß du nur einen einzigen fehlgeschlagenen Aufruf hast (und eine Sekunde Wartezeit sollte akzeptabel sein).
Was meinst du mit "kann nicht mit Zeigern umgehen"? Dass ich zB. nicht LB_GETCOUNT verwenden kann? Denn wenn diese Funktionen sofort zurückkehren, und die Nachricht noch nicht verarbeitet wurde, wo soll dann das Ergebnis sein?
Nein, damit meinte ich eher das Problem, was ich oben mit LB_SETTEXT angesprochen hatte - weil die Funktionen sofort zurückkehren, sind die übergebenen String-Daten womöglich nicht mehr gültig, wenn das Ziel endlich zur Verarbeitung kommt.
(hast du zufällig die MSDN in Reichweite? Wenn ja, empfiehlt sich ein Blick in die Funktionsbeschreibungen - speziell die "Remarks" Sektion ist immer wieder aufschlußreich)
-
Aber zur Abbruchbedingung kommt der Thread immer erst nach mehreren Aufrufen von SendMessageTimeout...
Oder soll ich einfach vor jedem dieser Aufrufe prüfen, ob exitThread nicht schon TRUE ist, und gegebenfalls returnen...?!
MSDN ist mir nicht fremd, ich bin aber einfach davon ausgegangen, dass die *Message*- Funktionen gleich funktionieren, sry.
MfG
-
Wenn Du SendMessage (auch SendMessageTimeout) über Threadgrenzen hi9nweg verwendest, hast Du von Deinem Multithreading garnichts mehr, alles wird synchronisiert, bis die Nachrichten abgearbeitet worden sind, als ob Alles in einem Thread lääääuft.
Lass SendMessage aus einem Thread in einen anderen einfach bleiben!