2010-11-29 2 views
3

J'utilise une bibliothèque tierce qui utilise beaucoup de threads.Envoyer un message directement à partir d'un thread à un objet sans utiliser le formulaire principal

Je viens de commencer à utiliser des messages pour communiquer de nouveau avec le thread principal à partir d'un thread. Tout fonctionne, mais en utilisant SendMessage la façon dont je décris ci-dessous semble lourde car le formulaire principal doit envoyer tous les messages. Y at-il un moyen d'envoyer un message directement à un cadre ou un objet, sans dépendre du formulaire principal?

au démarrage du programme:

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

Lorsque vous envoyez un message sans aucune donnée, je fais:

SendMessage(Application.MainForm.Handle, MyMessageNumber1) 

Ma principale forme a ceci:

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; 

En résumé: le Au-dessus de WndProc, il faut en savoir beaucoup plus que je ne voudrais sur tous les messages et à qui les envoyer.

Comment puis-je envoyer un message directement à partir d'un thread de manière à ce que n'importe quel objet puisse le recevoir?

Tous ces messages ne sont associés à aucune donnée. (Nous y reviendrons un autre jour!) :-)

TIA

+0

J'ai du mal à accepter l'idée que WndProc puisse en savoir trop sur les messages. La gestion des messages est le ** travail ** de WndProc. –

+0

#Rob Kennedy - Mais si le WndProc est sous la forme principale (comme je le pensais nécessaire, donc cette question) alors le formulaire principal devrait connaître toutes sortes de détails de code bas niveau afin qu'il puisse leur envoyer des messages. Pourquoi le formulaire principal doit-il connaître les détails internes d'un code de bas niveau alors que, comme le souligne Mason, le code de bas niveau peut explicitement capter le message? – RobertFrank

Répondre

2

D'autres formulaires et trames comportent également des poignées, et vous pouvez définir des méthodes de gestion des messages, puis publier le message directement dans le formulaire ou le cadre. (Ou contrôlez, d'ailleurs, si vous construisez vos propres commandes personnalisées.)

Voir http://docwiki.embarcadero.com/RADStudio/en/Declaring_a_New_Message-handling_Method pour un aperçu de la configuration des méthodes de traitement des messages.

+1

Soyez prudent avec ceci. La propriété TWinControl.Handle n'est PAS thread-safe. Si le HWND d'un contrôle est en train d'être recréé au moment de l'envoi du message, la lecture de la propriété Handle du contrôle depuis l'intérieur du thread peut avoir de sérieuses conséquences. Il est préférable d'utiliser AllocateHWND() pour définir un HWND dédié à la place. –

+0

@Remy Lebeau - Dans quel contexte le HWND d'un contrôle est-il en train d'être recréé? Si, par exemple, mon contrôle fait partie du formulaire principal d'une application ou d'un cadre sur le formulaire principal, le HWND est-il jamais recréé après l'exécution du programme? – RobertFrank

+0

Oui, ça peut. TWinControl a une méthode publique RecreateWnd(). De nombreux setters de propriétés VCL appellent RecreateWnd() en interne lorsqu'une nouvelle valeur de propriété doit être appliquée à un HWND existant. Plutôt que d'utiliser SetWindowLong() (qui serait plus efficace et ne nécessite pas de recréer le HWND), la plupart des contrôles VCL qui manipulent les attributs HWND appellent simplement RecreateWnd(), puis redéfinissent CreateWnd() pour appliquer les valeurs de propriétés actuelles à chaque HWND qui est créé pendant la durée de vie du contrôle. –

4

Oui, vous pouvez. Vous pouvez utiliser AllocateHWND pour allouer un handle de fenêtre dans n'importe quel objet. Cette poignée peut être utilisée pour envoyer des messages.

Mais votre problème peut résider dans le SendMessage. Si vous utilisez PostMessage au lieu de SendMessage, l'appel sera immédiatement renvoyé. PostMessage n'attend pas qu'un message soit traité. Donc, si vous n'avez pas besoin du résultat du message et que vous n'avez pas besoin d'envoyer des références aux données de thread, vous pouvez simplement utiliser PostMessage.

+1

Je vois que quelqu'un a downvoted cette réponse. C'est peut-être parce que vous n'avez pas besoin de créer un handle pour un Frame ou un autre WinControl qui a déjà un handle. Cependant, si vous voulez que * n'importe quel objet * puisse recevoir le message, vous devrez lui fournir un handle. – GolezTrol

+0

Et PostMessage est encore plus efficace pour la communication inter-thread si vous n'avez pas besoin d'envoyer des données. :) – GolezTrol

+0

Cela vaut aussi pour les contrôles. TTimer est un excellent exemple de contrôle non fenêtré qui utilise AllocateWND pour créer une fenêtre de réception des messages de temporisation. – GolezTrol

Questions connexes