Wenn wir eine Nachricht senden, " wenn das angegebene Fenster vom aufrufenden Thread erstellt wurde, wird die Fensterprozedur sofort als Subroutine " aufgerufen.
Aber " wenn das angegebene Fenster von einem anderen Thread erstellt wurde, wechselt das System zu diesem Thread und ruft die entsprechende Fensterprozedur auf. Nachrichten, die zwischen Threads gesendet werden, werden nur verarbeitet, wenn der empfangende Thread Nachrichtenabrufcode ausführt. " (aus der MSDN-Dokumentation für SendMessage
).
Nun verstehe ich nicht wie (oder, besser gesagt, wenn ) die Ziel-Windows-Prozedur aufgerufen wird. Natürlich wird der Ziel-Thread nicht vorweggenommen (der Programmzähler wird nicht geändert). Ich nehme an, dass der Anruf während einiger Wartefunktion geschieht (wie GetMessage
oder PeekMessage
), ist es wahr? Dieser Prozess ist irgendwo im Detail dokumentiert?
Update: Die Begründung dahinter wird durch das QS_SENDMESSAGE
-Flag von GetQueueStatus()
und MsgWaitForMultipleObjects()
erklärt:
Dies bedeutet zusammen mit zusätzlichen Anmerkungen in der MSDN-Dokumentation, dass eine Nachricht, die von einem anderen Thread gesendet wurde, tatsächlich in die Warteschlange gestellt wird. Sobald GetMessage
oder PeekMessage
aufgerufen wird, wird es vor jeder anderen geposteten Nachricht verarbeitet, indem es direkt an die Fensterprozedur gesendet wird.
Ich sehe hier einige Verwirrung.
Gemäß den MSDN-Dokumenten, wenn Sie die Nachrichtenwarteschlange des aktuellen Threads mit der Absicht der Nachrichtenverarbeitung berühren (z. B. wenn Sie PeekMessage
oder GetMessage
aufrufen), alle ausstehend gesendet ( dh nicht in die Warteschlange gestellte Nachrichten von anderen Threads werden behandelt - an die WndProc
übergeben - und dann wird die Nachrichtenwarteschlange überprüft, also:
DispatchMessage
und werden so schnell wie möglich bearbeitet:
WndProc
übergeben
PostThreadMessage
macht genau das, was es angibt - posts eine Nachricht in einer Thread-Warteschlange - solche Nachrichten werden nicht an ein Fenster geleitet und müssen explizit behandelt werden DispatchMessage
verarbeitet werden, sind diejenigen, die von PostMessage
oder einer Systemeinrichtung (Timer, Ereignisse, Benutzereingaben, etc.) erstellt wurden SendNotifyMessage
, SendMessageTimeout
oder SendMessageCallback
anstelle von plain SendMessage
zwischen verschiedenen Threads Weitere Informationen finden Sie im Abschnitt "Bemerkungen" des Eintrags MSDN PeekMessage
.
Kurze Antwort: Wenn der Ziel-Thread GetMessage (oder PeekMessage) gefolgt von DispatchMessage aufruft, wird die SendMessage vom anderen Thread empfangen und behandelt.
Ich bin nicht sicher, ob die empfangene SendMessage andere Nachrichten in der Warteschlange vorwegnimmt oder nicht. In beiden Fällen ist eine SendMessage von einem Thread zum anderen wie: "Veröffentlichen Sie diese Nachricht in der Nachrichtenwarteschlange des anderen Threads. Geben Sie diese zurück, wenn der Thread die Verarbeitung beendet hat".
Ein Jetzt für eine Antwort, nach der Sie nicht gefragt haben:
Wenn ich Interaktionen zwischen dem Haupt-UI-Thread und einem Arbeitsthread programmiere, versuche ich generell, die Verwendung von SendMessage zu vermeiden. Wenn Sie nicht vorsichtig sind, können Sie in eine Situation geraten, in der beide Threads gegeneinander festgefahren sind. (Stellen Sie sich den Fall vor, dass der Hauptthread WaitForSingleObject aufruft, damit der Worker-Thread abgeschlossen wird, der Worker-Thread jedoch bei SendMessage zurück zum UI-Thread blockiert wird.)
Jedes Fenster ist mit einem Thread verknüpft. Sie können GetWindowThreadProcessId
verwenden, um den Thread jedes Fensters abzurufen. Wenn Sie eine Nachricht an einen Windows-Server von einem anderen Thread in Bezug auf PostThreadMessage
senden, wird die Nachricht in der Nachrichtenwarteschlange des Threads platziert. Der Thread muss eine get-message-Schleife haben (mit GetMessage
zum Beispiel), um die Nachrichten zu erhalten und dort zur Fensterprozedur des Fensters zu senden.
Wenn Sie SendMessage
statt PostThreadMessage
aufrufen, rufen Sie die Windows-Prozedur direkt auf, ohne sie in die Nachrichtenwarteschlange zu stellen. Einige nicht in Warteschlangen eingereihte Nachrichten werden auch sofort an die Zielfensterprozedur gesendet, wobei die Systemnachrichtenwarteschlange und die Threadnachrichtenwarteschlange umgangen werden. (Siehe Ссылка ). Der Hauptgrund dafür, SendMessage
anstelle von PostThreadMessage
zu verwenden, wenn Sie Informationen von einem anderen Windows (Steuerelement) wie einen Text von einem anderen Steuerelement während der Verarbeitung einer anderen Nachricht lesen möchten. Sie sollten dies nur tun, wenn es wirklich benötigt wird. Also, wenn Sie SendMessage
verwenden, um eine Nachricht an ein Fenster von einem anderen Thread zu senden, muss Ihr aktueller Thread für einige Zeit blockiert werden.
Es kann eine gute Idee sein, PostThreadMessage
oder SendMessageCallback
anstelle von SendMessage
zu verwenden, wenn es möglich ist.