Problem mit SendMessage/PostMessage
-
Sorry, aber ich bin gestern nicht mehr dazu gekommen.
Mich würde ja ein NULL beim Konstruktor von TForm schon stutzig machen.
Wie kann ich denn sonst eine Klasse erstellen, die Windowsnachrichten empfangen kann? Es handelt sich dabei um kein GUI-Element.
Hier kommt meine Execute-Methode.
void __fastcall CANReceiver::Execute() { CANMessage *message; int count = 0; int waitingMS = 100; int sleepTime = 500; SendMessage(mCANPort->Handle, CPM_STATUS_CHANGED, NULL, (LPARAM)2); while(!Terminated) { Sleep(sleepTime); // warten auf event DWORD rV = WaitForSingleObject(mReceiveEvent, waitingMS); if(rV != WAIT_TIMEOUT) { XLevent event;// = new XLevent[CAN_QUEUE_LEVEL]; unsigned int eventCount = CAN_QUEUE_LEVEL; XLstatus status = xlReceive(*mPortHandle, &eventCount, &event); if(status != XL_ERR_QUEUE_IS_EMPTY ) { bool extended = false; int a = -1; unsigned long id = event.tagData.msg.id; AnsiString text(xlGetEventString(&event)); count++; switch (event.tag) { case XL_RECEIVE_MSG: /* TODO : Auswertung der Flags fehlt noch */ if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_ERROR_FRAME) a = 0; else if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_OVERRUN) a = 1; else if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_REMOTE_FRAME) a = 2; else if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_TX_COMPLETED) a = 3; else if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_TX_REQUEST) a = 4; else if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_NERR) a = 5; else if(event.tagData.msg.flags & XL_CAN_MSG_FLAG_WAKEUP) a = 6; else { if((event.tagData.msg.id & XL_CAN_EXT_MSG_ID) != 0) { extended = true; event.tagData.msg.id ^= XL_CAN_EXT_MSG_ID; // delete extended bit } message = new CANMessage(event.tagData.msg.id, event.tagData.msg.data, event.tagData.msg.dlc, extended); SendMessage(mCANPort->Handle, CPM_MESSAGE_RECEIVED, NULL, (LPARAM)message); } // Nachricht auslesen, verpacken und an CANPort übergeben break; case XL_CHIP_STATE: XLstatus status; switch (event.tagData.chipState.busStatus) { case XL_CHIPSTAT_ERROR_ACTIVE: status = CANBUS_ERROR_ACTIVE; break; case XL_CHIPSTAT_ERROR_PASSIVE: status = CANBUS_ERROR_PASSIV; break; case XL_CHIPSTAT_BUSOFF: status = CANBUS_BUSOFF; break; } // end switch (busStatus) if(mLastStatus != status) { mLastStatus = status; SendMessage(mCANPort->Handle, CPM_STATUS_CHANGED, NULL, (LPARAM)status); } break; default: ; }//end switch (event.tag) }// end if (status }// end if (WaitForSingleObject }// end while }
-
Das erste SendMessage ist nur zu Testzwecken eingebaut. Wenn ich die while-Bedingung auf false setze, erscheint eine Fehlermeldung mit Fehlernummer 1400 (invalid window handle).
Anscheinend passt also was mit meinem Empfänger, wobei es mich sehr wundert, dass trotzdem eine Zeit lang Nachrichten dort ankommen und verarbeitet werden.
-
Ich habe das Fenster nun einfach anzeigen lassen und alles klappt nach einem Show()-Aufruf. Nun blende ich das einfach aus und es stört nicht in der Anzeige.
Es wird also irgendetwas mit der Show()-Methode ausgelöst, was erst das Empfangen der Nachrichten möglich macht. Kann mir hier jemand sagen, was das sein könnte? Dann kann ich meinen Code evtl. so umbauen, dass ich das Show() nicht aufrufen brauche. Zwar stört es nicht, aber beim Starten der SW flackert die Anzeige kurz. Das könnte dann auch weg sein.
-
DarkGuardian schrieb:
Sorry, aber ich bin gestern nicht mehr dazu gekommen.
Mich würde ja ein NULL beim Konstruktor von TForm schon stutzig machen.
Wie kann ich denn sonst eine Klasse erstellen, die Windowsnachrichten empfangen kann? Es handelt sich dabei um kein GUI-Element.
Mit etwas WinAPI... PostThreadMessage wäre wohl dein Freund... Ausserdem hab ich noch was im Usenet gefunden:
Gambit (TeamB schrieb:
Inside your Execute() method, you need to use the Win32 API function
Get/PeekMessage() in a loop. Call PeekMessage() before entering the loop,
so that the message queue will get created (it's not created by default) and
be ready for use inside the loop.Kann es sein, dass dein Thread loslegt, bevor das Fenster vorhanden ist?
Kann es sein, dass dein Fenster weg ist, bevor der Thread zu Ende gelaufen ist?
-
Hier noch ne ausführliche Usenet-Diskussion zum Thema Threads mit Message-Queue. Remy Lebeau (Gambit) ist einer der kompetentesten Teilnehmer in den Borland Newsforen und ein Mitentwickler der Winshoes / Indy-Komponenten von TeamB. Es gibt da jemanden der ihm widerspricht. Dabei handelt es sich aber - wie sich im Verlauf der Diskussion rausstellt - um ein Misverständnis des Widersprechenden.
-
Kann es sein, dass dein Thread loslegt, bevor das Fenster vorhanden ist?
Kann es sein, dass dein Fenster weg ist, bevor der Thread zu Ende gelaufen ist?Der Thread wird im Konstruktor des Fensters erzeugt. Daher sollte es da unproblematisch sein. Zudem löscht sich der Thread selbst, nachdem die Execute-Methode beendet wurde. Im Destruktor wird der Thread beendet und dann auf das Ende gewartet.
Seitdem ich das Fenster zur Anzeige bringe (wenn auch versteckt), treten die Probleme nicht mehr auf.Zum Rest werde ich erst mal die Diskussion lesen müssen.
-
Also so wie ich das lese, muss ich bei PostThreadMessage auf eine eingehende Nachricht beim Empfänger pollen. Da dieser in meinem Fall aber Teil des Hauptthreads ist, kommt das nicht in Frage (genauso wie PostMessage).
Ich sehe zumindest momentan keinen anderen Weg, als die Nachrichten mit SendMessage zu senden.
-
Das Selbe machst du auch bei SendMessage. Da besteht absolut kein Unterschied, ausser das SendMessage auf die Bearbeitung der Nachricht wartet, während PostMessage einfach weiter geht.
-
Bei SendMessage übernimmt Windows das Pollen intern. Ich brauche nirgendwo eine Schleife, die mit GetMessage o.Ä. aufruft. Und aus diesem Grund kann ich auch SendMessage und nicht PostMessage einsetzen.
-
Du hast da was nicht verstanden:
Post und SendMessage tun beide exakt das Selbe: Sie setzen beim Empfänger eine Nachricht in die Queue. Einziger Unterschied: Sendmessage wartet, bis die versandte Nachricht vom Empfänger aus der Queue geholt wurde.
Der Empfänger wiederum muss egal mit welcher Methode die Nachricht versandt wurde immer die Queue mit z.B. GetMessage pollen und anfallende Nachrichten verarbeiten.
-
Dann frage ich mich nur, warum Nachrichten mit SendMessage ankommen und verarbeitet werden. Mit PostMessage passiert das nicht.
Daher gehe ich davon aus, dass bei SendMessage etwas im System ausgelöst wird, was die Verarbeitung der Nachricht auslöst.
Ursprünglich hatte ich es so verstanden, dass beide Methoden eine Nachricht in der Queue ablegen und nur SendMessage auf eine Rückmeldung wartet. Wenn ich aber nun von den Erfahrungen in meinem Projekt ausgehe, scheint SendMessage eine Verarbeitung anzustoßen und PostMessage nicht (wobei ich PostMessage noch nicht mit GetMessage getestet habe (es passt nicht ins Konzept)).
-
DarkGuardian schrieb:
Dann frage ich mich nur, warum Nachrichten mit SendMessage ankommen und verarbeitet werden. Mit PostMessage passiert das nicht.
Weil offenbar SendMessage irgend einen Effekt auf die Laufzeit deines Threads hat und PostMessage nicht? - Btw: Wer löscht eigentlich deine Message-Objekte die du erstellst?
DarkGuardian schrieb:
Ursprünglich hatte ich es so verstanden, dass beide Methoden eine Nachricht in der Queue ablegen und nur SendMessage auf eine Rückmeldung wartet.
Exakt so ist es auch.
DarkGuardian schrieb:
Wenn ich aber nun von den Erfahrungen in meinem Projekt ausgehe, scheint SendMessage eine Verarbeitung anzustoßen und PostMessage nicht
Nur weil vermurkste Software merkwürdige Nebeneffekte erzielt, muss das noch lange nicht für alle gelten. Ich hatte nie probleme mit PostMessage. Ausser ich hab die Queue überfüllt mit zuvielen Nachrichten.
DarkGuardian schrieb:
(wobei ich PostMessage noch nicht mit GetMessage getestet habe (es passt nicht ins Konzept)).
Klar... denn Weder Post- noch SendMessage haben was mit GetMessage zu tun.
-
Weil offenbar SendMessage irgend einen Effekt auf die Laufzeit deines Threads hat und PostMessage nicht?
Der Unterschied ist der, dass mein Thread auf eine Rückmeldung wartet. Bei PostMessage macht er das natürlich nicht. Aber selbst wenn mein Thread nur ein SendMessage aufruft und danach beendet wird, wird die Nachricht verarbeitet und mit PostMessage geht das nicht.
Btw: Wer löscht eigentlich deine Message-Objekte die du erstellst?
Die werden vom empfangenen Objekt gelöscht. Speicherlecks konnte ich auch noch nicht feststellen (zumindest sagt CodeGuard dazu nichts).
Ich hatte nie probleme mit PostMessage. Ausser ich hab die Queue überfüllt mit zuvielen Nachrichten.
Wie ich schon einmal erklärt habe, kann ich nicht auf eingehende Nachrichten pollen. Und laut API müsse diese Nachrichten mit GetMessage oder PeekMessage abgerufen werden. Zumindest sagt mir das die Hilfe vom C++Builder. Ich weiß nicht woher du deine Informationen hast, aber die stehen im Gegensatz zu meinen aus der Hilfe.
-
DarkGuardian schrieb:
Wie ich schon einmal erklärt habe, kann ich nicht auf eingehende Nachrichten pollen.
Tust du doch sowieso schon... nur merkst dus nicht.
DarkGuardian schrieb:
Und laut API müsse diese Nachrichten mit GetMessage oder PeekMessage abgerufen werden. Zumindest sagt mir das die Hilfe vom C++Builder. Ich weiß nicht woher du deine Informationen hast, aber die stehen im Gegensatz zu meinen aus der Hilfe.
Äh. Was genau führt dich zu der irrigen Annahme, dass zwischen Post- und SendMessage ein Unterschied in der Verarbeitung besteht?
Nochmal zum Mitschreiben für Analphabeten:
Funktionen die vom Sender aufgerufen werden
SendMessage setzt eine Nachricht in die Queue und wartet, bis sie verarbeitet wurde.
PeekMessage setzt eine Nachricht in die Queue und kehrt gleich danach zurück.Funktionen die vom Empfänger aufgerufen werden
Um die MessageQueue zu leeren, führt der Empfänger zyklisch die Funktion GetMessage aus, welche die Nachrichten aus der Queue lädt und verarbeitet diese zyklisch. Dabei ist der Versandweg schlicht wurst.