IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API, COM et SDKs Delphi Discussion :

[Win32] Messages intra-appli


Sujet :

API, COM et SDKs Delphi

  1. #1
    Membre habitué
    Développeur .NET
    Inscrit en
    Juin 2002
    Messages
    274
    Détails du profil
    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2002
    Messages : 274
    Points : 174
    Points
    174
    Par défaut [Win32] Messages intra-appli
    Bonjour

    Bon je ne suis pas familier des messages Windows mais je voudrais les utiliser simplement pour mettre à jour toutes les fiches de mon appli lors d'un changement de langage. Auparavant j'utilisais une méthode publique du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TfrmMain.ChangeLang;
    (...)
    if frmList <> nil then 
      frmList.UpdateCaptions;
    if frmAbout <> nil then
      frmAbout.UpdateCaptions;
    ..mais j'utilise maintenant les "class procedure" pour certaines fenêtres, donc si je fais "TMaFiche.Execute" je n'ai plus de variable "maFiche: TMaFiche" à laquelle accéder pour appeler sa méthode UpdateCaptions. D'où les messages.

    D'après un conseil trouvé je ne sais plus où j'utilise WM_NOTIFY avec un WParam perso (pas besoin de se créer un message spécifique alors que l'existant peut convenir. Pas tant que ça finalement, j'y reviendrai).
    J'arrive donc à intercepter le WM_NOTIFY ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    procedure WMNotify(var Msg: TMessage); message WM_NOTIFY;
    Mais pas dans le DefaultHandler !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TfrmAbout.DefaultHandler(var Message);
    begin
      //inherited DefaultHandler(Message);
     
     if TMessage(Message).Msg = WM_NOTIFY then begin
        if TMessage(Message).WParam = C_MON_PARAM then begin
          UpdateCaptions;
          TMessage(Message).Result := 1;
        end;
      end;
     
      inherited DefaultHandler(Message);
    end;
    Que le inherited soit placé à la fin ou pas, le message n'est pas "reçu". Quelqu'un saurait-il pourquoi ?

    Mais la vraie question n'est pas là : je suis maintenant obligé dans ma fiche principale de tester les fenêtres les unes après les autres pour leur envoyer à chacune le message :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    AHandle := FindWindow(PChar('TfrmAbout'), nil);
    if AHandle <> 0 then
      PostMessage(AHandle, WM_NOTIFY, C_MON_PARAM, 0);
    // A répéter pour les x fenêtres existantes
    Si j'envoie avec un handle HWND_BROADCAST aucune fiche ne reçoit, même si je remplace WM_NOTIFY par un message perso en constante WM_USER + ... et/ou en utilisant RegisterWindowMessage.
    Y a t-il un moyen d'éviter les envois multiples et successifs à chaque fiche ?? Merci.


    PS: WM_NOTIFY est "délicat" à manipuler ; s'il n'est pas traité dans la fenêtre à qui il est destiné --> Violation d'Accès !! A cause je pense de sa structure particulière (paramètre NMHDR). En tout cas ça surprend au début

  2. #2
    Membre habitué
    Développeur .NET
    Inscrit en
    Juin 2002
    Messages
    274
    Détails du profil
    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2002
    Messages : 274
    Points : 174
    Points
    174
    Par défaut
    Ma question se résume à : comment envoyer un message dans la même application sans connaitre le Handle des fenêtres filles ?

    Rien à faire avec HWND_BROADCAST, les autres applis reçoivent mais pas la mienne.

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 754
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 754
    Points : 13 338
    Points
    13 338
    Par défaut
    En voyant ce que représente les paramètres de de WM_NOTIFY, je peux déjà te dire qu'un envoi asynchrone n'est pas possible dû à la libération de la structure avant le traitement par le destinataire. (d'où l'Acces Violation).

    Depuis Vista et l'UAC, la plupart des messages sont filtrés par l'UIPI et doivent être spécifiquement autorisés par le destinataire s'il est d'un niveau d'intégrité supérieur à ton application.

    Citation Envoyé par paradise Voir le message
    Ma question se résume à : comment envoyer un message dans la même application sans connaitre le Handle des fenêtres filles ?
    Les fiches sont listées sous Screen.Forms. Tu peux ensuite lancer un Perform sur chacune d'elles.

  4. #4
    Membre habitué
    Développeur .NET
    Inscrit en
    Juin 2002
    Messages
    274
    Détails du profil
    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2002
    Messages : 274
    Points : 174
    Points
    174
    Par défaut
    Ouep c'est ce que j'ai fini par faire, avec un message perso pour éviter les "risques" dus à un WM_NOTIFY non maitrisé.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    var
      hTemp: THandle;
    ...
    for I := 0 to Screen.FormCount - 1 do begin
      hTemp := FindWindow(PChar(String(Screen.Forms[I].ClassName)), nil);
      if hTemp <> 0 then
        PostMessage(hTemp, WM_LANG_CHANGE, 0, 0);
      end;

    Je me demandais juste s'il existait un équivalent broadcast intra-application, apparemment non.

  5. #5
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    c'est une mauvaise idée de partir dans des FindWindows et des messages

    il suffit de créer une liste globale dans laquelle s'inscrit toute fenêtre désirant être notifiée des changements et d'envoyer les notifications à cette liste.

    le plus souple est alors d'utiliser des interfaces

    voici un code à la main sans test

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    var
      NotificationList: TList = nil;
     
    type
      TUserEvent = (event1, event2);
     
      TNotificationInterface = Interface
        procedure Notification(Event: TUserEvent);
      end;
     
    procedure RegisterForNotification(Obj: TObject);
    begin
      if NotificationList = nil then
        NotitificationList := TList.Create;
      NotificationList.Add(Obj);
    end;
     
    procedure UnregisterForNotification(Obj: TObject);
    begin
      if NotificationList <> nil then
       NotificationList.Remove(Obj);
    end;
     
    procedure NotifyObjects(Event: TUserEvent);
    var
      Index: Integer;
      Obj: TObject;
      Intf: TNotificationInterface;
    begin
      if NotificationList = nil then
       Exit;
      for Index := 0 to NotificationList.count - 1 do
      begin
       Obj := NotificationList[Index];
       Intf := Obj as TNotificationInterface;
       Intf.Notify(Event);
      end;
    end;
    tout objet (pas forcément une fiche) qui supporte TNotificationInterface pourra être ajouté à la liste pour recevoir les notification.

  6. #6
    Membre habitué
    Développeur .NET
    Inscrit en
    Juin 2002
    Messages
    274
    Détails du profil
    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2002
    Messages : 274
    Points : 174
    Points
    174
    Par défaut
    En effet c'est bien plus propre, mais mon souci de base reste le même : les fenêtres filles sont gérées via une class procedure
    donc je n'ai pas d'instance à laquelle accéder, en l'occurrence à transmettre à RegisterForNotification...

  7. #7
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    Citation Envoyé par paradise Voir le message
    En effet c'est bien plus propre, mais mon souci de base reste le même : les fenêtres filles sont gérées via une class procedure
    donc je n'ai pas d'instance à laquelle accéder, en l'occurrence à transmettre à RegisterForNotification...
    mais c'est aux fenêtres qui veulent être notifiées de s'enregistrer ! dans TFrmAbout.Create elle appelle RegisterForNotification(Self) et dans le Destroy elle s'en retire.

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 754
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 754
    Points : 13 338
    Points
    13 338
    Par défaut
    Citation Envoyé par paradise Voir le message
    Je me demandais juste s'il existait un équivalent broadcast intra-application, apparemment non.
    Il existe au niveau TApplication, mais c'est une méthode privée. Elle ne fait rien de plus que ce que j'ai mentionné.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TApplication.NotifyForms(Msg: Word; WParam: WPARAM = 0; LParam: LPARAM = 0);
    var
      I: Integer;
    begin
      for I := 0 to Screen.FormCount - 1 do
        Screen.Forms[I].Perform(Msg, WParam, LParam);
    end;

  9. #9
    Membre habitué
    Développeur .NET
    Inscrit en
    Juin 2002
    Messages
    274
    Détails du profil
    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Juin 2002
    Messages : 274
    Points : 174
    Points
    174
    Par défaut
    Oui Paul c'est ce que j'ai fait, puis j'ai eu une erreur de transtypage incorrect sur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Intf := Obj as INotificationInterface;
    ... alors je n'ai pas cherché plus loin.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [win32] message WM_LMOUSEBUTTON
    Par NiamorH dans le forum Windows
    Réponses: 1
    Dernier message: 25/05/2007, 19h51
  2. [win32] messages de fenetre WM_SIZE et WM_ACTIVATE
    Par NiamorH dans le forum Windows
    Réponses: 12
    Dernier message: 25/05/2007, 19h31
  3. [WIN32] - Messages hors fenetre
    Par buzzkaido dans le forum Windows
    Réponses: 7
    Dernier message: 24/01/2007, 13h47
  4. Réponses: 6
    Dernier message: 20/10/2005, 21h36
  5. Réponses: 4
    Dernier message: 24/08/2005, 16h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo