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

EDI Delphi Discussion :

Interdire des instances multiples d'une application


Sujet :

EDI Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Août 2010
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 26
    Par défaut Interdire des instances multiples d'une application
    Bonjour,

    Comment interdire le lancement de plusieurs instances d'une application (VCL ou Console) ?
    Si une instance est en cours d'exécution (masquée par une autre application, réduite dans la barre des tâches, ...), je souhaite restaurer l'application et la mettre au 1er plan.

    Merci pour votre aide.

    Thierry RICHET

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 124
    Par défaut
    UniqueInstance Delphi se trouve assez vite, c'est via un message pour la mise au premier plan, parfois cela fonctionne moins bien que si c'est l'application externe qui remet l'autre devant.

    c'est un
    Comment n'instancier qu'une seule fois un programme ?


    Ajoute ensuite un FindWindow pour trouver la fenêtre et faire un SetForegroundWindow, comme dans ce code Programme qui se ferme si une autre instance est déjà démarrée

    Je ne l'ai pas fait depuis longtemps donc faut mettre au neuf ce code, l'unicode en particulier

    Citation Envoyé par ShaiLeTroll Voir le message

    Un vieux code de 2002 (il peut être même plus vieux, c'est inspiré d'un exemple de Phidels) qui en plus met la fenêtre de la précédente instance au premier plan
    Avec les Delphi gère différemment la MainForm cela peut ne pas fonctionner (MainFormOnTaskbar à False)

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    unit Unique_Instance;
     
    {
     dans la projet :
     
    Application.Initialize;
    Application.Title := 'Titre du Programme';
    if not UniqueInstance(Application.Title) then Exit;
    Application.CreateForm(TMenuFrm, MenuFrm);
    Application.Run;
     }
     
     
    interface
     
    uses
        forms,windows,sysutils;
     
    type
      PFindWindowStruct = ^TFindWindowStruct;
      TFindWindowStruct = record
        Caption: string;
        ClassName: string;
        WindowHandle: THandle;
      end;
     
    function UniqueInstance(Nom: String): boolean;
    procedure GoMainApp(Nom: String);
    function FindAWindow(ACaption: string): THandle;
    function EnumWindowsProc(hWindow: hWnd;lParam : LongInt): Boolean; stdcall;
     
    implementation
     
    function UniqueInstance(Nom: String): boolean;
    begin
      CreateMutex(nil, False, PChar(Nom));
      Result := GetLastError <> ERROR_ALREADY_EXISTS;
      if not Result then GoMainApp(Application.Title);
    end;
     
     
     
    procedure GoMainApp(Nom: String);
    var
      ActifHnd: THandle;
    begin
         ActifHnd:= FindAWindow(Nom);
         if ActifHnd <> 0 then begin
           ShowWindow(ActifHnd, SW_NORMAL);
           SetForegroundWindow(ActifHnd);
         end;
    end;
     
    function FindAWindow(ACaption: string): THandle;
    var
      WindowInfo: TFindWindowStruct;
    begin
         with WindowInfo do begin
              Caption:= ACaption;
              ClassName:= '';
              WindowHandle:= 0;
              EnumWindows(@EnumWindowsProc, LongInt(@WindowInfo));
              result:= WindowHandle;
              //showmessage(IntTostr(result));
     
         end;
    end;
     
    function EnumWindowsProc(hWindow: hWnd;lParam : LongInt): Boolean; stdcall;
    var
      lpBuffer: PChar;
      WindowCaptionFound: bool;
      ClassNameFound: bool;
     
    begin
         GetMem(lpBuffer, 255);
         Result:= True;
         WindowCaptionFound:= False;
         ClassNameFound:= False;
         try
            if GetWindowText(hWindow, lpBuffer, 255) > 0 then
               if Pos(PFindWindowStruct(lParam).Caption, StrPas(lpBuffer)) = 1 then begin
                  WindowCaptionFound:= true;
                  if PFindWindowStruct(lParam).ClassName = '' then
                ClassNameFound:= True
             else if GetClassName(hWindow, lpBuffer, 255) > 0 then
                  if Pos(PFindWindowStruct(lParam).ClassName, StrPas(lpBuffer)) > 0 then
                     ClassNameFound:= True;
          end;
        if (WindowCaptionFound and ClassNameFound) then begin
          PFindWindowStruct(lParam).WindowHandle:= hWindow;
          Result:= False;
        end;
     
      finally
        FreeMem(lpBuffer, sizeof(lpBuffer^));
      end;
    end;
     
    end.
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 969
    Par défaut
    Les conditions pour passer une fenêtre au premier plan par SetForegroundWindow sont très restrictives et ne seront pas satisfaites au démarrage de la nouvelle instance.

    Peut peut-être fonctionner si précédé de SetWindowPos(PrevWnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE);

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 124
    Par défaut
    Je confirme que si ça fonctionnait bien sous Win98 et Win2K, c'était bien moins efficace en Win Vista, j'ai abandonné depuis longtemps ce genre de fantaisie, ce n'est même pas une chose que j'ai dans ma lib perso que je maintiens depuis 20 ans, c'est resté un code à l'époque de D4/D5 déjà en D7 sous XP, je ne le faisais plus.

    Attention, en DEBUG sous Delphi, le comportement n'est pas le même que si tu lances l'EXE en autonome, ça aussi cela peut jouer des tours, on croit que cela fonctionne mais c'est un effort de bord du débogage.


    Idem, SetForegroundWindow était précédé souvent de ShowWindow + SetWindowPos
    Je confirme, c'est très capricieux !


    Sinon SetForegroundWindow, je l'utilise surtout pour EXCEL, une instance lancée ou manipulé par OLE par le programme en cours et même là, c'est capricieux malgré que le programme Delphi soit le créateur de l'instance Excel, mais parfois en forçant un peu :

    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
    //------------------------------------------------------------------------------
    procedure SetForegroundWindowAsync(const AWindowExcelCaption: string; Delay: Cardinal = INFINITE);
    begin
      TThread.CreateAnonymousThread(
        procedure
        var
          Tentative: Integer;
          ExcelWnd: HWND;
          ForegroundedExcel: Boolean;
        begin
          Tentative := 0;
          repeat
            if Delay <> INFINITE then
              Sleep(Delay);
     
            ExcelWnd := FindWindow(nil, PChar(AWindowExcelCaption));
            ForegroundedExcel := (SetForegroundWindow(ExcelWnd) or LongBool(SetActiveWindow(ExcelWnd)))
              and (GetForegroundWindow() = ExcelWnd);
     
            Inc(Tentative);
          until ForegroundedExcel or (Tentative > 5);
     
        end).Start();
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre averti
    Inscrit en
    Août 2010
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 26
    Par défaut
    Merci pour votre réponse.
    La solution proposée dans la FAQ répond à mon problème.

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

Discussions similaires

  1. Interdire des lancements multiples d'une application
    Par JJJJJ dans le forum Débuter
    Réponses: 7
    Dernier message: 23/02/2008, 19h19
  2. Réponses: 4
    Dernier message: 05/05/2005, 17h34
  3. [C#] Lier des boutons radio dans une application mobile
    Par Loïc56 dans le forum Windows Forms
    Réponses: 2
    Dernier message: 22/04/2005, 14h00
  4. Réponses: 2
    Dernier message: 12/10/2004, 14h04
  5. Réponses: 5
    Dernier message: 13/11/2003, 17h57

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