2010-11-29 12 views
3

Ich verwende eine 3rd-Party-Bibliothek, die viele Threads verwendet.Senden Sie eine Nachricht direkt aus einem Thread an ein Objekt, ohne das Hauptformular zu verwenden

Ich habe gerade begonnen, Nachrichten zu verwenden, um zurück zum Haupt-Thread von einem Thread zu kommunizieren. Es funktioniert alles, aber das Verwenden von SendMessage, wie ich unten beschreibe, scheint umständlich, da das Hauptformular alle Nachrichten senden muss. Gibt es eine Möglichkeit, eine Nachricht direkt an einen Rahmen oder ein Objekt zu senden, ohne vom Hauptformular abhängig zu sein?

beim Programmstart:

MyMessageNumber1 := RegisterWindowMessage('MyUniqueID1'); 
MyMessageNumber2 := RegisterWindowMessage('MyUniqueID2'); 

Wenn Sie eine Nachricht ohne Daten zu senden, das tue ich:

SendMessage(Application.MainForm.Handle, MyMessageNumber1) 

Meine Hauptform hat dies:

procedure WndProc(var Message: TMessage); override; 
if (Message.Msg = MyMessageNumber1) 
    ... call a frame or other object's method that handles this particular message 
else if (Message.Msg = MyMessageNumber2) then 
    ... call another .... 
else 
    inherited; 

Zusammengefasst: die über WndProc muss weit mehr wissen, als ich über alle Nachrichten vorziehen würde und wem sie zu schicken.

Wie kann ich eine Nachricht direkt aus einem Thread senden, so dass jedes Objekt sie empfangen kann?

Für alle diese Nachrichten sind keine Daten zugeordnet. (Wir werden an einem anderen Tag zu das!) :-)

TIA

+0

Ich finde es schwierig, die Vorstellung zu akzeptieren, dass WndProc jemals zu viel über Nachrichten wissen könnte. Die Verarbeitung von Nachrichten ist der ** Job ** von WndProc. –

+0

#Rob Kennedy - Aber wenn der WndProc in der Hauptform ist (wie ich dachte, war notwendig, also diese Frage), dann würde die Hauptform über alle Arten von Details von Low-Level-Code wissen müssen, damit es Nachrichten an sie versenden konnte. Warum sollte das Hauptformular irgendwelche internen Details eines Low-Level-Codes wissen müssen, wenn, wie Mason darauf hinweist, der Low-Level-Code die Nachricht explizit abfangen kann? – RobertFrank

Antwort

2

Andere Formulare und Rahmen haben auch Handles, und Sie können Methoden für die Nachrichtenverarbeitung definieren und dann die Nachricht direkt in das Formular oder den Rahmen stellen. (Oder steuern Sie, wenn Sie Ihre eigenen benutzerdefinierten Steuerelemente erstellen.)

Einen Überblick über das Einrichten von Methoden zur Nachrichtenverarbeitung finden Sie unter http://docwiki.embarcadero.com/RADStudio/en/Declaring_a_New_Message-handling_Method.

+1

Seien Sie vorsichtig damit. Die TWinControl.Handle-Eigenschaft ist NICHT Thread-sicher. Wenn das HWND eines Steuerelements zum Zeitpunkt des Sendens der Nachricht ausgelastet ist, kann das Lesen der Eigenschaft Handle des Steuerelements aus dem Thread schwerwiegende Folgen haben. Es empfiehlt sich, AllocateHWND() zu verwenden, um stattdessen ein dediziertes HWND zuzuweisen. –

+0

@Remy Lebeau - In welchem ​​Kontext wird die HWND eines Controls neu erstellt? Wenn beispielsweise mein Steuerelement Teil des Hauptformulars einer Anwendung oder eines Rahmens auf dem Hauptformular ist, wird das HWND nach dem Ausführen des Programms erneut erstellt? – RobertFrank

+0

Ja, kann es. TWinControl verfügt über eine öffentliche RecreateWnd() - Methode. Viele VCL-Eigenschaften-Setter rufen RecreateWnd() intern auf, wenn ein neuer Eigenschaftswert auf ein vorhandenes HWND angewendet werden muss. Anstatt SetWindowLong() zu verwenden (was effizienter wäre und das HWND nicht neu erstellen müsste), rufen die meisten VCL-Steuerelemente, die HWND-Attribute manipulieren, einfach RecreateWnd() auf und überschreiben dann CreateWnd(), um die aktuellen Eigenschaftswerte auf jedes HWND anzuwenden das wird während der Lebensdauer der Steuerung erstellt. –

4

Ja, Sie können. Sie können AllocateHWND verwenden, um ein Fensterhandle in einem beliebigen Objekt zuzuordnen. Mit diesem Handle können Nachrichten gesendet werden.

Aber Sie Problem möglicherweise in der SendMessage liegen. Wenn Sie PostMessage statt SendMessage verwenden, wird der Aufruf sofort zurückgegeben. PostMessage wartet nicht auf die Verarbeitung einer Nachricht. Wenn Sie also das Nachrichtenergebnis nicht benötigen und keine Referenzen auf Thread-Daten senden müssen, können Sie einfach PostMessage verwenden.

+1

Ich sehe, dass jemand diese Antwort abgelehnt hat. Das liegt möglicherweise daran, dass Sie kein Handle für einen Frame oder ein anderes WinControl erstellen müssen, das bereits über ein Handle verfügt. Wenn Sie jedoch möchten, dass * irgendein Objekt * die Nachricht empfangen kann, müssen Sie dieses Objekt mit einem Handle versehen. – GolezTrol

+0

Und PostMessage ist noch effizienter für die Kommunikation zwischen den Threads, wenn Sie keine Daten senden müssen. :) – GolezTrol

+0

Das gilt auch für Kontrollen. TTimer ist ein großartiges Beispiel für ein Steuerelement ohne Fenster, das AllocateWND verwendet, um ein Fenster zum Empfangen von Timer-Nachrichten zu erstellen. – GolezTrol

Verwandte Themen