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 :

Comment récupérer le handle d'une fenêtre seulement depuis un Mutex ?


Sujet :

API, COM et SDKs Delphi

  1. #1
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut Comment récupérer le handle d'une fenêtre seulement depuis un Mutex ?
    Salut à tous

    J'ai créé un Mutex pour limiter le lancement de mon application à une seule fois.
    Seulement, j'aimerais maintenant passer l'application au premier plan si elle est déjà lancée et également, pouvoir envoyer des messages à cette application.

    Je me suis servi de cette entrée de la FAQ: http://delphi.developpez.com/faq/?pa...tion#1instance pour le mutex.

    Seulement, si je passe le handle du mutex créé dans SetForegroundWindow, évidemment, ça ne fonctionne pas...
    Je sais bien qu'il existe FindWindow mais, problème, le Caption de la fiche en question est variable

    La question est donc:
    Comment récupérer le handle de la fenêtre ou de l'application déjà lancée depuis le mutex récupéré?

    merci d'avance

  2. #2
    Membre expérimenté

    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    685
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 685
    Points : 1 608
    Points
    1 608
    Par défaut
    Pourquoi ne pas utiliser la base de registres pour stocker le handle de la fenêtre à afficher ? La première instance de l'appli écrit son handle de fenêtre, et la seconde instance, détectant le mutex créé, lit le handle et appelle SetForegroundWindow.

  3. #3
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Salut Reisubar

    Merci pour ta réponse

    En fait, que ce soit la BDR ou bien un fichier, je trouve que ça fait "sale". J'aimerais éviter autant que possible l'ajout de machins temporaires de cet acabit C'est déjà assez le foutoir sur les ordis et dans la BDR comme ça
    En revanche, si ce n'est pas possible comme je recherche, tu viens de me donner une solution de rechange

  4. #4
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut Pedro

    J'ai fait ceci récemment.
    Parallèlement au Mutex je définis un Message via RegisterWindowMessage. Dans le DPR, lors de l'échec à la création du mutex je diffuse le message en broadcast qui sera traité par la 1° instance.

    le DPR:

    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
    var
      hMutex: Cardinal;
    begin
      MyMsg := RegisterWindowMessage('RestoreMyAppMessage');
      SetLastError(NO_ERROR);
      hMutex := CreateMutex(nil, False, 'MyAppMutex');
      if GetLastError = ERROR_ALREADY_EXISTS then
        PostMessage(HWND_BROADCAST, MyMsg, 0, 0)
      else
      begin
        Application.Initialize;
        Application.CreateForm(TForm1, Form1);
        Application.Run;
        if hMutex <> 0 then
          ReleaseMutex(hMutex);
      end;
    end.
    et dans la form principale:
    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
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
      private
        { Déclarations privées }
        procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
      MyMsg: Cardinal;
     
    implementation
     
    {$R *.dfm}
     
    { TForm1 }
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Application.OnMessage := AppMessage;
    end;
     
    procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
    begin
      if Msg.message = MyMsg then
      begin
        Application.Restore;
        SetForegroundWindow(Application.MainForm.Handle);
        Handled := True;
      end;
    end;
    A noter bizarrement que parfois l'appli est bien mise au 1° plan, et parfois le bouton de la barre des tâches clignote en orange, sans vraiment comprendre pourquoi.

    @+ Claudius

  5. #5
    Membre expérimenté

    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    685
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 685
    Points : 1 608
    Points
    1 608
    Par défaut
    A noter bizarrement que parfois l'appli est bien mise au 1° plan, et parfois le bouton de la barre des tâches clignote en orange, sans vraiment comprendre pourquoi.
    L'utilisation de SetForegroundWindow est très stricte, il y a des tonnes de conditions qui font que Windows peut refuser de faire passer ta fenêtre au premier plan (cf MSDN). En l'occurence, si ton application est inactive (pas le focus), elle ne peut pas forcer à se réafficher, ce qui explique le clignotement que tu expliques. Pour que ca marche à coup sûr, il faut que ce soit l'application active qui initie l'affichage, c'est à dire qu'il faut que tu connaisses le handle de l'autre instance... voilà pourquoi je passais par le registre

  6. #6
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Citation Envoyé par Reisubar Voir le message
    Pour que ca marche à coup sûr, il faut que ce soit l'application active qui initie l'affichage, c'est à dire qu'il faut que tu connaisses le handle de l'autre instance...
    Le SetForegroundWindow sera bien appelé par la 1° instance (donc avec son handle connu), la 2° se limitant à faire un broadcast. D'où mes questions "existentielles" sur ces 2 types de comportements.

    A noter que je n'ai pas cherché plus avant, le résultat me suffisant globalement.

    @+

  7. #7
    Membre expérimenté

    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    685
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 685
    Points : 1 608
    Points
    1 608
    Par défaut
    Le SetForegroundWindow sera bien appelé par la 1° instance (donc avec son handle connu), la 2° se limitant à faire un broadcast. D'où mes questions "existentielles" sur ces 2 types de comportements.
    Justement. Si j'ai bien compris, la seconde fois, ce n'est pas l'application active qui demande à afficher une fenêtre, mais c'est la première instance "prévenue" par message qui demande à "s'auto-afficher", ce que Microsoft vise à empêcher via le flash dans la bare des tâches.

  8. #8
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Ah OK je vois ce que tu veux dire. Je vais aller faire tour par curiosité du côté de la MSDN.

    @+

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 612
    Points : 25 303
    Points
    25 303
    Par défaut
    Pourquoi ne pas faire un FindWindow sur la classe au lieu du texte ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FindWindow('TBiduleMainForm', nil)
    Mais sinon depuis XP, il est effectivement plus difficile d'afficher des fenêtre, d'où le flash, mais il reste la possibilité, d'envoyer un message à la fenêtre trouvé, et qu'elle même fasse son BringToFront ...

  10. #10
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Pourquoi ne pas faire un FindWindow sur la classe au lieu du texte ?
    Ah oui tiens, je vais essayer
    Citation Envoyé par ShaiLeTroll Voir le message
    mais il reste la possibilité, d'envoyer un message à la fenêtre trouvé, et qu'elle même fasse son BringToFront ...
    Si je ne me trompe pas, c'est ce que propose Cl@udius

    Merci pour toutes ces infos, je teste et je vous tiens au jus!

  11. #11
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Bon je viens d'essayer et malheureusement, FindWindow me renvoie invariablement 0
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    InstHandle := FindWindow('TTopoPRMainForm', nil);
    J'ai même renommé ma fiche principale pour être sûr de mon coup mais nada...
    Je crois que je vais faire un fichier temporaire qui contient le handle. Ca sera plus simple... Mais c'est dommage

  12. #12
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 612
    Points : 25 303
    Points
    25 303
    Par défaut
    Sinon passe par un EnumWindows, tu trouveras ta fenêtre normalement, ...

    Effectivement, la méthode du Message, c'est l'idée de claudius, mais lui passait par un HWND_BROADCAST, qui donc envoie un message à toutes les applications ... c'est pour cela qu'il utilise RegisterWindowMessage pour avoir un message non utilisé par les autres applications
    Je proposais de tenter le FindWindow sur la classe pour ne faire qu'un SendMessage que vers l'appli concernée ...

    faut juste remplacer dans le code de Cl@audius qui doit fonctionner normalement, et qui me semble moins barbare que la BDR ou un fichier ...

    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Application.Restore;
    Application.BringToFront;
    Alors, j'y pense, mais j'ai fait cela pour une application qui se mets en NotifyIcon, et donc quand je lançais le programme une deuxième fois, je lui fait faire un affichage de fenêtre, tient comme ça

    Donc ma fenêtre caché, avec toujours la même classe et la même caption (tu peux très bien bidouillé une fenêtre invisible que tu chercheras à la place de la MainForm)
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    class procedure TNotifyTaskBarXXXForm.Popup();
     
      function FindAllWindow(const ClassName, WindowName: string; Index: Integer = 0): THandle;
      var
         HandleFound, Parent: THandle;
         lpRes : array[0..256] of Char;
         StrClass: string;
         StrCaption: string;
         iChild: Integer;
         lpClassName, lpWindowName: PChar;
      begin
         Result := 0;
         iChild := -1;
     
         if Trim(ClassName) <> '' then lpClassName := PChar(ClassName) else lpClassName := nil;
         if Trim(WindowName) <> '' then lpWindowName := PChar(WindowName) else lpWindowName := nil;
         Parent := GetActiveWindow(); // Peu Importe c'est quoi, on rebalaye tout !
     
         HandleFound := GetWindow(Parent, GW_HWNDFIRST);
         while HandleFound > 0 do
         begin
            GetClassName(HandleFound, lpRes, SizeOf(lpRes));
            StrClass := lpRes;
            GetWindowText(HandleFound, lpRes, SizeOf(lpRes));
            StrCaption := lpRes;
     
            if ((ClassName = '') or SameText(ClassName, StrClass)) and ((WindowName = '') or SameText(WindowName, StrCaption)) then
            begin
               Inc(iChild);
               if iChild >= Index then begin
                  Result := HandleFound;
                  Exit;
               end;
            end;
     
            HandleFound := GetWindow(HandleFound, GW_HWNDNEXT);
         end;
      end;
     
    var
       Index: Integer;
       Handle: THandle;
    begin
      Index := 0;
      repeat
          Handle := FindAllWindow(ClassName, '', Index);
          Inc(Index);
          SendMessage(Handle, WM_MYTOPEVENT, 0, 0);
      until Handle <= 0;
    end;

  13. #13
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Sinon passe par un EnumWindows, tu trouveras ta fenêtre normalement, ...
    Bah, j'ai fait un fichier temporaire qui contient le handle et ça marche (heureusement )
    Je me compliquerai la vie une autre fois
    Citation Envoyé par ShaiLeTroll Voir le message
    Effectivement, la méthode du Message, c'est l'idée de claudius, mais lui passait par un HWND_BROADCAST, qui donc envoie un message à toutes les applications ...
    Oui tu as raison. mea culpa

    Merci pour votre aide

  14. #14
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Forcément, si tu édites après que j'ai répondu

    J'ai remplacé comme tu as dit par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Application.Restore;
    Application.BringToFront;
    Appelé par un autre message lancé par PostMessage à l'appli à remettre devant.
    Et ça marche impeccable

    Sinon, je vais garder ma méthode "barbare" (fin de citation )
    La tienne est assez brutale aussi: parcourir toutes les fiches jusqu'à la bonne

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 612
    Points : 25 303
    Points
    25 303
    Par défaut
    Citation Envoyé par Pedro Voir le message
    Forcément, si tu édites après que j'ai répondu
    Ben, ça m'arrive souvent, je planche sur une idée, et je peux mettre près de 1 heure à concoter une réponse, et parfois je m'édite sans voir que le temps à passer et qu'une réponse est venue, ...

    Sinon, tant que ça fonctionne, et puis si tu met le fichier à la racine de l'exe ou dans un dossier temporaire (via GetTemporaryPath), et que tu nettoie derrière toi, ben, ça pose pas de problème ...

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

Discussions similaires

  1. Récupérer le handle d'une fenêtre précise
    Par AMS010 dans le forum Windows
    Réponses: 1
    Dernier message: 04/07/2008, 16h11
  2. comment obtenir le handle d'une fenètre
    Par DarkPoster14 dans le forum Visual C++
    Réponses: 2
    Dernier message: 30/04/2008, 18h49
  3. Réponses: 14
    Dernier message: 02/04/2008, 22h17
  4. Réponses: 3
    Dernier message: 26/07/2007, 18h28
  5. Coment récupérer le handle d'une fenêtre
    Par robocop2776 dans le forum MFC
    Réponses: 2
    Dernier message: 30/10/2005, 22h21

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