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

Langage Delphi Discussion :

Ouvrir depuis l'explorateur windows


Sujet :

Langage Delphi

  1. #1
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut Ouvrir depuis l'explorateur windows
    Bonjour,

    Je bloque depuis ce matin sur un problème que je croyais simple.
    Je cherche à ouvrir une application (delphi 7) depuis l'explorateur Windows et récupérer les fichiers ou les dossiers sélectionnés.

    Mon code est simple, j'ai simplement :

    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
    procedure TMain1.FormActivate(Sender: TObject);
    begin
      ListParams;
    end;
     
    procedure TMain1.ListParams;
    var
      i: Integer;
    begin
      ListBox1.Clear;
     
      if (ParamCount = 1) then
        ListBox1.Items.Add('No param')
      else
        for i:=1 to ParamCount do
          ListBox1.Items.Add(ParamStr(i));
    end;
    Cette partie fonctionne bien. Je récupère bien les paramètres que je sélectionne.

    J'ajoute ensuite (manuellement pour le moment) :

    • HKCR\Directory\shell\MonApp\ : Chaine (défaut) = "MonAPP Ouvrir les dossiers"
    • HKCR\Directory\shell\MonApp\command\ : Chaine "icon" = "D:\src\MonApp\app.exe,0"
    • HKCR\Directory\shell\MonApp\command\ : Chaine (défaut) = "D:\src\MonApp\app.exe" "%V"


    • HKCR\*\shell\MonApp\ : Chaine = "MonAPP Ouvrir les fichiers"
    • HKCR\*\shell\MonApp\command\ : Chaine "icon" = "D:\src\MonApp\app.exe,0"
    • HKCR\*\shell\MonApp\command\ : Chaine (défaut) = "D:\src\MonApp\app.exe" "%1"


    Le menu apparait bien, mais cela ne fonctionne pas .
    Mon application s'ouvre autant de fois, que je sélectionne de dossier ou de fichiers.
    Aucun fichier ou dossier n'est listé dans mon application.

    Quelqu'un saurait-il m'aider ?
    Merci d'avance.

  2. #2
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    bonjour,

    J'ai fais de nouveaux tests ce matin. Cela fonctionne finalement.
    J'ai juste modifié la ligne suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (ParamCount = 0) then
    Par contre, dans le cas où l'on sélectionne plusieurs fichiers, est-ce qu'il y a un moyen que l'application ne s'ouvre qu'une fois en récupérant la liste des fichiers.
    Je n'ai pas trouvé d'infos à ce sujet.

    Merci d'avance.

  3. #3
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Deux Sèvres (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 661
    Points : 3 630
    Points
    3 630
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par oneDev Voir le message
    bonjour,

    J'ai fais de nouveaux tests ce matin. Cela fonctionne finalement.
    J'ai juste modifié la ligne suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (ParamCount = 0) then
    Par contre, dans le cas où l'on sélectionne plusieurs fichiers, est-ce qu'il y a un moyen que l'application ne s'ouvre qu'une fois en récupérant la liste des fichiers.
    Je n'ai pas trouvé d'infos à ce sujet.

    Merci d'avance.
    Bonjour,
    Dans ce cas, je ferai en sorte que mon application ne puisse se lancer qu'une fois (mono instance) en utilisant un mutex (https://delphi.developpez.com/faq/?p...s-un-programme). En cas d'instance de l'application déjà en cours d'exécution, et avant que la seconde instance ne se ferme, il faut envoyer le paramètre reçu à la première instance.
    Mon site - Mes tutoriels - GitHub - N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  4. #4
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    C'est effectivement ce que j'avais cru comprendre.
    Je ne m'attendais à tomber sur un problème aussi compliqué :s

    En parcourant la FAQ, je pense que je peux utiliser le code suivant :

    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
    var
      hwn: HWND;
    begin
      hwn := IsPrevInstance;
     
      if (hwn = 0) then
      begin
        Application.Initialize;
        Application.CreateForm(TMain1, Main1);
        Application.Run;
      end
      else
      begin
        AfficherInstance(hwn);
      end;
    end.
    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
    function IsPrevInstance: HWND;
    var
      ClassName: array[0..255] of char;
      Title: string;
    begin
      Title := Application.Title;
      Application.Title := 'Yo!';
      { On change le titre, car on trouverait toujours une application lancée, (la notre). }
      try
        GetClassName(Application.Handle, ClassName, 255);
        { Met dans ClassName le nom de la classe de l'application. }
        Result := FindWindow(ClassName, PChar(Title));
        { Renvoie le Handle de la 1ère fenêtre de Class (Type) ClassName, et le titre de l'application. }
      finally
        Application.Title := Title; { Restauration du vrai titre. }
      end;
    end;
     
    procedure AfficherInstance(InstHandle: HWND);
    begin
      { Restaurer l'application si minimisée }
      ShowWindow(InstHandle, SW_RESTORE);
      { Mettre la première instance en premier plan : }
      SetForegroundWindow(InstHandle);
     
      // passer paramètres à la première instance
     
      { Fin de la deuxième instance }
      Application.Terminate;
    end;
    Par contre, je ne sais pas comment envoyer des paramètres à la première instance.

  5. #5
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Deux Sèvres (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 661
    Points : 3 630
    Points
    3 630
    Billets dans le blog
    2
    Par défaut
    Il faudra gérer dans ton application un nouveau message spécifique.
    Principe de fonctionnement :
    1. Tu définies un nouveau message utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const WM_TESTINSTANCE = WM_USER + 1;
    Le +1 peut être remplacé par le nombre souhaité si l'application gère déjà d'autres messages utilisateurs.

    2. Lorsque l'on détecte la présence de la première instance, on récupère son handle et on lui envoie le message utilisateur défini précédemment avec le paramètre reçu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Atom := GlobalAddAtomA(PAnsiChar(AnsiString(paramstr(1))));
          Result := SendMessage(Handle, WM_TESTINSTANCE , Atom, 0) <> 1;
          GlobalDeleteAtom(Atom);
          halt;
    on passe par un atom (ajouter au besoin winapi.Windows dans la clause uses) pour identifier de manière unique la chaine de caractères. On envoie le message et on ferme l'application.

    3. Ajouter à l'application la procédure qui va réagir lorsqu'elle reçoit un message de type WM_TESTINSTANCE :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    procedure WndProc(var Message: TMessage);
    avec une définition du type :
    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
    procedure WndProc(var Message: TMessage);
    var PC: array[0..MAX_PATH] of AnsiChar;
    	len: integer;
    	s: AnsiString;
    begin
        Message.Result := 0;
        if Message.Msg = WM_TESTINSTANCE then begin
           Accept := True;
           len := GlobalGetAtomNameA(Message.wParam, PC, MAX_PATH - 1);
           SetLength(s, len);
           if len > 0 then
                Move(PC[0], s[1], len);
            if FileExists(s) then ouvrirFichier(s);  // <== voir votre procédure de chargement de fichier
            Message.Result := 1;
            if Application.MainForm <> nil then
    	  SetForegroundWnd(Application.MainForm.Handle);
        Dispatch(Message);
    end;
    On récupère la string depuis l'atom, si le fichier pointé par la chaine de caractères lue existe, on le charge et on affiche au premier plan la fenêtre de la première instance.

    Je n'ai pas testé le code mais cela devrait être quelque chose qui ressemble à cela dans le principe.

    Bonne année 2020 !!!
    Mon site - Mes tutoriels - GitHub - N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  6. #6
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    Merci de ta réponse, je vais tester tout cela.

    J'ai eu des urgences à traiter et je n'avais pas encore eu le temps de me remettre sur ce sujet.

    Et bonne année !

  7. #7
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    J'ai quelques soucis.
    J'ai ajouté WndProc dans la fenêtre principale.
    J'ai 2 erreurs avec Accept et Dispatch qui ne sont pas reconnus.
    J'ai donc dû les commenter pour que cela compile.

    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
    procedure TMain1.WndProc(var Message: TMessage);
    var
      PC: array[0..MAX_PATH] of AnsiChar;
      len: integer;
      s: AnsiString;
    begin
      Message.Result := 0;
     
      if (Message.Msg = WM_TESTINSTANCE) then
      begin
    //    Accept := True;
        len := GlobalGetAtomNameA(Message.wParam, PC, MAX_PATH - 1);
        SetLength(s, len);
     
        if (len > 0) then
          Move(PC[0], s[1], len);
     
        Main1.AddParam(s);  // <== voir votre procédure de chargement de fichier
     
        Message.Result := 1;
     
        if (Application.MainForm <> nil) then
          SetForegroundWindow(Application.MainForm.Handle);
      end;
    //  Dispatch(Message);
    end;
    Du coup, cela ne fonctionne pas, SendMessage, me renvoi 0.
    Une idée du problème.

  8. #8
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    Bonjour,

    j'ai fait un petit projet en reprenant les solutions que tu avais choisis


    à l'utilisation il faut penser à supprimer, du *.dpr, la ligne (si présente):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        { ne doit pas être utilisé }
        //Application.MainFormOnTaskBar := True;
    sinon le code ne fonctionnera pas avec

    Code source:

    RunOnce.zip


    Cordialement,

    @+

  9. #9
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    Merci beaucoup, cela fonctionne très bien grâce à ton code.

    A quoi sert la ligne suivante ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    initialization
      WM_RUNONCE_DATA_MSG := RegisterWindowMessage('RunOnce Data Message');
    Je ne l'ai pas ajouté dans mon code et cela fonctionne correctement.

  10. #10
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    Citation Envoyé par oneDev Voir le message
    Merci beaucoup, cela fonctionne très bien grâce à ton code.

    A quoi sert la ligne suivante ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    initialization
      WM_RUNONCE_DATA_MSG := RegisterWindowMessage('RunOnce Data Message');
    Je ne l'ai pas ajouté dans mon code et cela fonctionne correctement.
    cette ligne permet de définir un "WindowMessage" qui soit unique et adapté à la communication entre applications.
    Citation Envoyé par RegisterWindowMessage MSDN
    Définit un nouveau message de fenêtre qui est garanti unique dans tout le système. La valeur du message peut être utilisée lors de l'envoi ou de la publication de messages.
    Syntaxe
    C++


    UINT RegisterWindowMessageA( LPCSTR lpString );


    Paramètres

    lpString

    Type: LPCTSTR

    Le message à enregistrer.
    Valeur de retour

    Type: Type: UINT

    Si le message est enregistré avec succès, la valeur de retour est un identifiant de message compris entre 0xC000 et 0xFFFF.

    Si la fonction échoue, la valeur de retour est zéro. Pour obtenir des informations d'erreur étendues, appelez GetLastError .
    Remarques

    La fonction RegisterWindowMessage est généralement utilisée pour enregistrer des messages pour communiquer entre deux applications coopérantes.

    Si deux applications différentes enregistrent la même chaîne de messages, les applications renvoient la même valeur de message. Le message reste enregistré jusqu'à la fin de la session.

    N'utilisez RegisterWindowMessage que lorsque plusieurs applications doivent traiter le même message. Pour envoyer des messages privés au sein d'une classe de fenêtre, une application peut utiliser n'importe quel entier de la plage WM_USER à 0x7FFF. (Les messages de cette plage sont privés d'une classe de fenêtre et non d'une application. Par exemple, des classes de contrôle prédéfinies telles que BUTTON , EDIT , LISTBOX et COMBOBOX peuvent utiliser des valeurs de cette plage.)
    je te conseil d'utiliser cette version qui te garanti que le message sera envoyé au bon destinataire
    voir à toutes les applications qui ont enregistrées ce message avec un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PostMessage(HWND_BROADCAST, WM_RUNONCE_DATA_MSG ...
    ce qui n'est pas le cas de:
    const WM_TESTINSTANCE = WM_USER + 1;
    qui est déjà utilisé en interne par la VCL (voir la partie en violet)
    et qui pourrait dans certains cas livrer le message au mauvais destinataire.

    Cordialement,

    @+

  11. #11
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    Ok, merci de ces précisions

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

Discussions similaires

  1. Ouvrir un fichier (explorateur windows)
    Par sushis dans le forum Windows Presentation Foundation
    Réponses: 2
    Dernier message: 28/04/2012, 11h18
  2. [WSS3] pb "ouvrir avec l'explorateur windows"
    Par chatroux dans le forum SharePoint
    Réponses: 2
    Dernier message: 25/02/2009, 09h20
  3. Ouvrir l'explorateur windows depuis un lien
    Par black is beautiful dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 11/04/2007, 09h38
  4. Réponses: 2
    Dernier message: 03/02/2006, 12h02
  5. Réponses: 4
    Dernier message: 25/01/2005, 22h14

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