Fermer envoi d'un message entre applications : passage d'entiers

GERER LES MESSAGES WINDOWS

ENVOI DE MESSAGES ENTRE APPLICATIONS

Dernière mise à jour : 22/09/02

Garantir un n° de message unique

Lorsque l'on envoie des messages entre applications, il est préférable de ne pas employer la méthode vue précédemment du style WM_USER +1 pour définir le numéro de notre message.

Nous allons utiliser l'API RegisterWindowMessage qui permet de récupérer un numero de message unique en fonction de la chaine de caractère qu'on lui passe en paramétre. Cela évite d'utiliser les WM_USER +.. et donc évite de se retrouver avec 2 applications qui utilisent les mêmes numéros de message à destination d'une autre.

Attention à bien choisir sa chaîne de caractères car 2 appels à RegisterWindowMessage renvoient le même résultat si la chaîne de caractères est la même.

  • Concrètement, ajouter la ligne suivante dans le OnCreate de la Form1:
NumMessage:=RegisterWindowMessage('Message perso de application');

NumMessage aura été déclaré par exemple dans la partie private de la déclaration de TForm1 ainsi :

private
NumMessage : UINT;// num de notre message

 

Les messages s'envoient vers des objets référencés par leur Handle

Il faut donc être capable de connaître le Handle de la fenêtre de destination.

Une première solution est de faire appel à la fonction FindWindow qui à partir du titre de la fenêtre renvoit le Handle de cette fenêtre (pour une TForm, c'est ce qui s'affiche dans son titre c'est à dire la propriété TForm.caption)

Cette solution est la plus facile. Nous l'utiliserons donc. Par contre, nous examinerons par la suite d'autres solutions car celle-ci a un gros inconvénient : elle oblige à avoir un titre d'application suffisament compliqué pour être sur qu'une autre application ne possède pas une fenêtre du même nom !.

  • Placez deux SpinEdit (onglet Exemple). Nommez les respectivement SpinEditWParam et SpinEditLParam
  • Placez, un bouton sur la Form1 de l'application émétrice de message.
  • Implémentez son évènement OnClick de la façon suivante :
procedure TForm1.ButtonEnvoieMessageClick(Sender: TObject);
var h:THandle;
    WParam1:WPARAM;
    LParam1:LPARAM;
begin
    h:=FindWindow(nil,'Fenêtre réceptrice de messages');
    // on va envoyer dans notre message le contenu des SpinEdit
    // que l'on a placé sur la Form1.
    WParam1:=SpinEditWParam.Value;
    LParam1:=SpinEditLParam.Value;
    SendMessage(h, NumMessage,WParam1,LParam1);
end;

Un message référencé par NumMesage (celui qui a été défini par notre RegisterWindowMessage) sera envoyé à la fenêtre qui a pour Handle h c'est à dire à la fenêtre de notre application réceptrice qui a pour titre 'Fenêtre réceptrice de messages'

 

Implémentation du programme de réception du message

Notre Application réceptrice du message doit connaitre le numéro de message qu'il faudra intercepter. Il faut donc Y placer un RegisterWindowMessage avec en paramètre la même chaîne de caractères que dans le programme d'émission du message.
On va en profiter pour mettre notre titre de fenêtre conformément à ce que l'on a pris comme paramètre du FindWindow du programme d'envoie de message.

procedure TForm1.FormCreate(Sender: TObject);
begin
  NumMessage:=RegisterWindowMessage('Message perso de application');
  Form1.Caption:='Application réceptrice de messages';
end;


Si on s'en réfaire à ce que l'on a appris dans les autres chapitres du tutorial, on a envie d'avoir une procédure qui se déclenche à chaque fois que notre fenêtre reçoit le message.

Le problème est que l'on ne peut déclarer une telle procédure ainsi :

procedure WMMessagePerso(var Msg : TMessage); message WM_MESSAGEPERSO
avec WM_MESSAGEPERSO=NumMessage

puisque WM_MESSAGEPERSO est une constante. Dans cette déclaration; on a pas moyen de lui afecter une valeurqui soit celle de NumMessage après le RegisterWindowMessage.

Il faut donc employer une autre méthode.

 

Utilisation de DefaultHandler

DefaultHandler est une méthode qui se charge de traiter tous les messages qui ne sont pas gérés directement par le contrôle (ici Form1).
On va donc surcharger cette méthode afin d'intercepter les messages non gérés par notre Form1.

  • Placez deux SpinEdit (onglet Exemple). Nommez les respectivement SpinEditWParam et SpinEditLParam.
  • Modifiez votre code pour obtenir :
unit Unit1ReceptionMessage;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Spin;;

type
  TForm1 = class(TForm)
    LabelNumMessage: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    NumMessage : UINT;// num de notre message
  public
    procedure DefaultHandler(var Message); override;
  end;

var
  Form1 : TForm1;

implementation

{$R *.DFM}

procedure TForm1.DefaultHandler(var Message);

begin
  inherited DefaultHandler(Message);// appel de la procédure dont 
			        // on a héritée
  if TMessage(Message).Msg = NumMessage then
  begin
    //récupération des paramètres accompagnant le message:
    // ces paramètres sont de type WPARAM et LPARAM
    // c'est à dire en réalité des LongInt
    // Ce qui vous permet de transmettre n'importe quel nombre
    // y compris en bricolant un peu des réels
    SpinEditWParam.Value:=TMessage(Message).WParam;
    SpinEditLParam.Value:=TMessage(Message).LParam;
  end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  NumMessage:=RegisterWindowMessage('Message perso de application');
  Form1.Caption:='Application réceptrice de messages';
end;

end.

Lancez les exe des 2 applications, testez. Si ça ne marche pas : téléchargez le source de l'exemple.

retour au sommaire