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 :

Créer un GUI pour une application console compilée


Sujet :

API, COM et SDKs Delphi

  1. #1
    Inactif
    Inscrit en
    Juillet 2010
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 29
    Points : 1
    Points
    1
    Par défaut Créer un GUI pour une application console compilée
    Salut à tous, j’espère que je suis dans la bonne catégorie ^^

    Actuellement j'ai une application console nommée "calc.exe" utilisable en ligne de commande, et j'essaye de créer une application visuel performante en Delphi permet d'utiliser cette application,

    Je déjà créer un GUI pour cette application console de la façon suivante :
    • On utilisant ShellExecute j’exécute l'application "calc.exe" avec les paramètres nécessaires
    • Je capture le texte sortie (Output), je l'analyse, et je le traite de la façon nécessaire


    Voici la fonction que j'utilise pour exécuter et capturer le output, je l'ai trouvé sur net
    Code delphi : 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
    function ExecCatch(App:String; ReturnOutput: Boolean): String;
    const
      ReadBuffer = 2400;
    var
      Security : TSecurityAttributes;
      ReadPipe,WritePipe : THandle;
      start : TStartUpInfo;
      ProcessInfo : TProcessInformation;
      Buffer : Pchar;
      BytesRead : DWord;
      Apprunning : DWord;
      Output: String;
    begin
      Output := '';
      With Security do begin
        nlength := SizeOf(TSecurityAttributes) ;
        binherithandle := true;
        lpsecuritydescriptor := nil;
      end;
      if Createpipe (ReadPipe, WritePipe,
                      @Security, 0) then begin
        Buffer := AllocMem(ReadBuffer + 1) ;
        FillChar(Start,Sizeof(Start),#0) ;
        start.cb := SizeOf(start) ;
        start.hStdOutput := WritePipe;
        start.hStdInput := ReadPipe;
        start.dwFlags := STARTF_USESTDHANDLES +
                             STARTF_USESHOWWINDOW;
        start.wShowWindow := SW_HIDE;
     
        if CreateProcess(nil,
               PChar(App),
               @Security,
               @Security,
               true,
               NORMAL_PRIORITY_CLASS,
               nil,
               nil,
               start,
               ProcessInfo)
        then
        begin
         repeat
          Apprunning := WaitForSingleObject
                       (ProcessInfo.hProcess,100) ;
          Application.ProcessMessages;
         until (Apprunning <> WAIT_TIMEOUT) ;
         if ReturnOutput then
          Repeat
            Application.ProcessMessages;
            BytesRead := 0;
            ReadFile(ReadPipe,Buffer[0],
            ReadBuffer,BytesRead,nil) ;
            Buffer[BytesRead]:= #0;
            OemToAnsi(Buffer,Buffer) ;
            Output := Output + String(Buffer) ;
          until (BytesRead < ReadBuffer) ;
       end;
       FreeMem(Buffer) ;
       CloseHandle(ProcessInfo.hProcess) ;
       CloseHandle(ProcessInfo.hThread) ;
       CloseHandle(ReadPipe) ;
       CloseHandle(WritePipe) ;
       end;
       result := Output;
    end;

    ça prend du temps, des fois ça BUG, SVP y a-t-il une méthode plus performante (non juste la fonction de capture) ? ou un composant ? toute proposition est la bienvenue, Merci d'avance .

  2. #2
    Kyrénoa
    Invité(e)
    Par défaut
    C'est lié à tes Pipes, leur utilisation est peu plus subtil, il faut créer un Pipe distinct pour Input et un autre pour Output comme dans cet exemple de la MSDN How to spawn console processes with redirected standard handles \ Comment appeler un processus console avec une redirection des canaux standards.

    Il y a une discussion sur le forum qui évoque cette complexité e qu'il soit nécessaire de faire autant d'appel CreatePipe que de canaux redirigés donc 3 si on utilise Input, Output et Error

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
          // Create the child output pipe.
          if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
             DisplayError("CreatePipe");
     
          // Create the child input pipe.
          if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
             DisplayError("CreatePipe");
     
          si.hStdOutput = hChildStdOut;
          si.hStdInput  = hChildStdIn;

    Note les variables marquée Tmp, si c'est utilisé avec CreateProcess+CreateThread il faut fournir des handles spécifiques, issu des Tmp avec DuplicateHandle

    Pour CreateProcess les variables en Tmp sont inutiles
    Dernière modification par Kyrénoa ; 09/03/2012 à 14h50.

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par Kyrénoa Voir le message
    Il y a une discussion sur le forum qui évoque cette complexité e qu'il soit nécessaire de faire autant d'appel CreatePipe que de canaux redirigés donc 3 si on utilise Input, Output et Error
    Tu fais surement référence au sujet Redirection des entrées/sorties du process
    où un problème de blocage des Pipes nécessitait des étranges CloseHandle !
    C'était une bidouille fonctionnelle mais un peu maladroite !

    Cela vient d'un amalgame entre Read\Write et Input\Output,
    on voit beaucoup de code utilisant un seul Pipe avec le Read dans Input et le Write dans Output,
    cela semble cohérent mais il l'erreur c'est d'utiliser le même Pipe !
    Il faut mettre le Read d'un Premier Pipe dans Input et le Write d'un Second Pipe dans Output

    J'avais donc proposer une version corrigée de l'utilisation de CreatePipe
    en m'inspirant de l'article MSDN mentionné !

    j'ai fait un code réutilisable proposant un CallBack qui permet par exemple un affichage en temps réel du flux de sortie dans des TMemo
    C'est d'ailleurs à ce moment que l'on peut faire Application.ProcessMessages();.
    Je l'ai utilisé pour récupérer des Flux XML généré par un Script PHP que je lançais via PHP.exe !
    Je l'ai utilisé pour d'autres programmes console qui renvoyait des informations sur le traitement qu'ils avaient effectués
    Je l'ai utilisé aussi avec DTK pour récupérer les informations extraites de fichier DICOM
    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

  4. #4
    Inactif
    Inscrit en
    Juillet 2010
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 29
    Points : 1
    Points
    1
    Par défaut
    J'ai aussi cette unité trouvé ici,
    http://www.delphibasics.info/home/de...dosapplication
    Code Delphi : 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
    unit uDOSOutput;
     
    interface
     
    uses Windows;
    function ExecuteCommand(CommandLine:string):string;
     
    var
      mCommand: string;
      mOutputs: string;
     
    implementation
     
    function ExecuteCommand(CommandLine:string):string;
    var
      PROC:       TProcessInformation;
      Ret:        LongBool;
      START:      TStartupInfo;
      SA:         TSecurityAttributes;
      hReadPipe:  THandle;
      hWritePipe: THandle;
      dBytesRead: DWORD;
      sBuff:      array[0..255] of Char;
    begin
      if Length(CommandLine) > 0 then
        mCommand := CommandLine;
      if Length(mCommand) = 0 then
      begin
        MessageBox(0, PChar('Command Line empty.'), PChar('Error'), MB_ICONEXCLAMATION);
        Exit;
      end;
      SA.nLength := SizeOf(TSecurityAttributes);
      SA.bInheritHandle := TRUE;
      SA.lpSecurityDescriptor := nil;
      Ret := CreatePipe(hReadPipe, hWritePipe, @SA, 0);
      if not Ret then
      begin
        MessageBox(0, PChar('CreatePipe() failed.'), PChar('Error'), MB_ICONEXCLAMATION);
        Exit;
      end;
      FillChar(START ,Sizeof(TStartupInfo), #0);
      START.cb := SizeOf(TStartupInfo);
      START.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
      START.hStdOutput := hWritePipe;
      START.hStdError := hWritePipe;
      Ret := CreateProcess(nil, PChar(mCommand), @SA, @SA, TRUE, NORMAL_PRIORITY_CLASS, nil, nil, START, PROC);
      if Ret <> TRUE then
      begin
        MessageBox(0, PChar('File or command not found.'), PChar('Error'), MB_ICONEXCLAMATION);
        Exit;
      end;
      Ret := CloseHandle(hWritePipe);
      mOutputs := '';
      repeat
        Ret := ReadFile(hReadPipe, sBuff, 255, dBytesRead, nil);
        mOutputs := mOutputs + Copy(sBuff, 1, dBytesRead);
      until Ret = FALSE;
      Ret := CloseHandle(PROC.hProcess);
      Ret := CloseHandle(PROC.hThread);
      Ret := CloseHandle(hReadPipe);
      ExecuteCommand := mOutputs
    end;
     
    end.
    pensez-vous que la fonction utilisée dans cette unité est plus performante que la première?

  5. #5
    Kyrénoa
    Invité(e)
    Par défaut
    je suis surpris de voir -1 à la reponse du troll c'etait exactement le sujet que je cherchais,
    merci pour avoir retrouver le lien et ta reponse !


    pour ta fonction z4k4r14, il y a une astuce dans ce code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      FillChar(START ,Sizeof(TStartupInfo), #0);
      START.cb := SizeOf(TStartupInfo);
      START.hStdOutput := hWritePipe;
      START.hStdError := hWritePipe;
    il n utilise pas hReadPipe et laisse NULL a hStdInput ce qui evite le blocage par contre cela doit consomme du processeur sans mettre de WaitForSingleObject, tu devrais utiliser ce code

  6. #6
    Inactif
    Inscrit en
    Juillet 2010
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 29
    Points : 1
    Points
    1
    Par défaut
    Merci beaucoup Kyrénoa c'est super sympa de ta part

    Je ne sais pas comment utiliser le code que tu m'a donné, je suis débutant, et j'ai aussi cette unité, je ne sais pas si elle est plus performante parmi les autres, que pense-tu Kyrénoa?


    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
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    unit UnitShell;
     
    interface
     
    uses
     Windows,StdCtrls, Messages, SysUtils;
     
    type
      TShellParameters = Record
    Memo:TMemo;
      end;
      PShellParameters = ^TShellParameters;
     
    var
      ShellThreadID : DWord;
     
    const
      ENTER = #10;  
     
    procedure ShellThread(P : Pointer); stdcall;
     
    implementation
     
    procedure ShellThread(P : Pointer); stdcall;
    //A este thread se le pasa como parametro un puntero a una esctructura
    //TShellParameters, que contiene el Socket al que hay que escribirle el
    //output de la consola.
     
    var
      StartupInfo: TStartupInfo;
      ProcessInformation: TProcessInformation;
      Secu:PSecurityAttributes;
      hPipeRead1, hPipeWrite1, hPipeRead2, hPipeWrite2, BytesRead, exitcode: dword;
      ComSpec:array [0..MAX_PATH] of char;
      Buf:array [0..1024] of char;
      MemBuf: array of char;
      msg: TMsg;
      TempStr : String;
      Memo:TMemo;
    begin
      Memo := PShellParameters(P)^.Memo;
     
      GetMem(Secu,sizeof(SECURITY_ATTRIBUTES));
      Secu.nLength := SizeOf(SECURITY_ATTRIBUTES);
      Secu.bInheritHandle := True;
      Secu.lpSecurityDescriptor := nil;
      CreatePipe(hPipeRead1, hPipeWrite1, Secu, 0);
      CreatePipe(hPipeRead2, hPipeWrite2, Secu, 0);
      //La variable de entorno COMSPEC contiene la ruta a el ejecutable de la shell
      //ejemplo C:\windows\system32\cmd.exe
      GetEnvironmentVariable('COMSPEC', ComSpec, sizeof(ComSpec));
      ZeroMemory(@StartupInfo, SizeOf(StartupInfo));
      StartupInfo.cb:=SizeOf(StartupInfo);
      StartupInfo.dwFlags:=STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
      StartupInfo.wShowWindow:=SW_HIDE;
      StartupInfo.hStdInput := hPipeRead2;
      StartupInfo.hStdOutput:= hPipeWrite1;
      StartupInfo.hStdError := hPipeWrite1;
      if CreateProcess(nil,ComSpec,Secu,Secu,TRUE,0,nil,nil,StartupInfo,ProcessInformation) = true
       then while true
        do begin //main loop
          GetExitCodeProcess(ProcessInformation.hProcess,{var }exitcode);
          if exitcode <> STILL_ACTIVE then break;
          TempStr := '';
          PeekNamedPipe(hPipeRead1,nil,0,nil, @BytesRead,nil);
          while BytesRead > 0
          do begin
            if ReadFile(hPipeRead1, Buf, sizeof(Buf), BytesRead,nil)
             then begin
             TempStr := TempStr + Copy(Buf, 1, bytesRead);
             end
             else break;
            PeekNamedPipe(hPipeRead1,nil,0,nil,@BytesRead,nil);
          end; //while BytesRead > 0
     
       if Length(TempStr) > 0 then //enviar datos
        begin
        if Memo.Enabled=true then
            begin
    Memo.Lines.Add(Tempstr);
            end
        else Break; //si el cliente no esta activo entonces se cierra
        end;
     
          GetMessage(msg, 0, 0, 0);
          if (msg.message = WM_ACTIVATE)
          then begin
            WriteFile(hPipeWrite2, pchar(msg.lParam)^, msg.wParam, BytesRead, nil);
            WriteFile(hPipeWrite2, #13#10, 2, BytesRead,nil);
          end;
        end; //main loop
     
      Memo.Enabled:=false;
     
      TerminateProcess(ProcessInformation.hProcess,0);
      CloseHandle(ProcessInformation.hProcess);
      CloseHandle(ProcessInformation.hThread);
      FreeMem(Secu);
      ShellThreadID := 0;
    end;
     
    procedure ShellPostMessageTimer;
    begin
    //esta funcion se pone en un timer para que postee mensajes cada segundo para
    //que la el thread de la shell no se bloquee en GetMessage
    if ShellThreadID <> 0 then
      PostThreadMessage(ShellThreadID, 0, 0, 0);
    end;
     
    begin
    ShellThreadID := 0;
    SetTimer(0, 0, 1000, @ShellPostMessageTimer);
    end.

  7. #7
    Kyrénoa
    Invité(e)
    Par défaut
    Citation Envoyé par z4k4r14 Voir le message
    Merci beaucoup Kyrénoa c'est super sympa de ta part
    Merci
    J ai juste repris des propos lus ici meme sur le forum

    Citation Envoyé par z4k4r14 Voir le message
    Je ne sais pas comment utiliser le code que tu m'a donné, je suis débutant
    ce code la ?
    Qui a pu mettre un -1 a ce code de 2008 alors que le systeme de notation existe seulement depuis 2010
    je l ai utiliser, il fonctionne, certains n ont pas du comprendre a quoi servait et
    les membres font parfois n importe koi

    le code d'appel est dans BtnTestDOSClick
    montre ton code d appel on peut te le corriger

    Citation Envoyé par z4k4r14 Voir le message
    et j'ai aussi cette unité, je ne sais pas si elle est plus performante parmi les autres, que pense-tu Kyrénoa?
    Pour ce dernier ShellThread de ton dernier message, je ne comprends pas le passage de parametre
    Dernière modification par Kyrénoa ; 13/03/2012 à 10h44.

  8. #8
    Inactif
    Inscrit en
    Juillet 2010
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 29
    Points : 1
    Points
    1
    Par défaut
    Merci, je ne sais pas pourquoi tu me parle du système de notation, je m'enfiche

  9. #9
    Kyrénoa
    Invité(e)
    Par défaut
    Citation Envoyé par z4k4r14 Voir le message
    Je ne sais pas comment utiliser le code que tu m'a donné, je suis débutant,
    as tu reussi ton appel de code ?
    quel code as tu choisi ?
    as tu resolu ton probleme ?

    le plus facile serait d utiliser le code de TSfcConsoleIOHandler qui est une tres bonne traduction de la msdn Creating a Child Process with Redirected Input and Output

    Citation Envoyé par z4k4r14 Voir le message
    Merci, je ne sais pas pourquoi tu me parle du système de notation, je m'enfiche
    c etait un message pour l ensemble des membres du forum qu il faut voter pour la qualite des reponses et non pour la personne qui les poste
    tu te sens viser par ma remarque ?
    Dernière modification par Domi2 ; 15/03/2012 à 15h06. Motif: Lien non pérenne

  10. #10
    Inactif
    Inscrit en
    Juillet 2010
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 29
    Points : 1
    Points
    1
    Par défaut
    Kyrénoa merci beaucoup pour tout l'effort que ta fait mec, tu m'a vraiment impressionné
    c etait un message pour l ensemble des membres du forum qu il faut voter pour la qualite des reponses et non pour la personne qui les poste
    ah ok
    tu te sens viser par ma remarque ?
    je suis ici pour parler de Delphi, sauf si tu veux être ma copine je rigole b1sur

  11. #11
    Kyrénoa
    Invité(e)
    Par défaut
    Citation Envoyé par z4k4r14 Voir le message
    Kyrénoa merci beaucoup pour tout l'effort que ta fait mec, tu m'a vraiment impressionné
    De rien !

    Pense au bouton en bas a droite de la page
    Si tu pouvais publier ton code d utilisation de CreateProcess\CreatePipe pour les prochains lecteurs cela serait sympa

  12. #12
    Inactif
    Inscrit en
    Juillet 2010
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Juillet 2010
    Messages : 29
    Points : 1
    Points
    1
    Par défaut
    sans problème mais seulement parce-que t une femme obéissante (mdr) je rigole reste cool

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

Discussions similaires

  1. créer raccourci clavier pour une application console
    Par aurelien3030 dans le forum C#
    Réponses: 6
    Dernier message: 08/03/2011, 18h03
  2. créer un installable pour une application
    Par sali lala dans le forum C#
    Réponses: 9
    Dernier message: 16/04/2009, 18h26
  3. faire un GUI pour une application console
    Par Truth dans le forum C++Builder
    Réponses: 4
    Dernier message: 27/02/2008, 15h05
  4. Réponses: 1
    Dernier message: 18/06/2007, 16h10
  5. Créer un patch pour une application
    Par oneTime dans le forum Windows
    Réponses: 7
    Dernier message: 17/02/2007, 22h28

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