Difference between revisions of "Executing External Programs/fr"

From Free Pascal wiki
Jump to navigationJump to search
(traduction des commentaires dans le programme)
Line 67: Line 67:
  
 
<pascal>
 
<pascal>
  // This is a demo program that shows how to launch
+
  // Ceci est un programme de démonstration qui montre
  // an external program and read from it's output.
+
  // comment lancer un programme externe et lire sa sortie
 
  program launchprogram;
 
  program launchprogram;
 
   
 
   
  // Here we include files that have useful functions
+
  // Ici on inclue les fichiers qui ont les fonctions et procédures
  // and procedures we will need.
+
  // dont nous avons besoin
 
  uses  
 
  uses  
 
   Classes, SysUtils, Process;
 
   Classes, SysUtils, Process;
 
   
 
   
  // This is defining the var "AProcess" as a variable  
+
  // Ceci définit la variable "AProcess" comment variable
  // of the type "TProcess"
+
  // de type "TProcess". On ajoute aussi une TStringList
// Also now we are adding a TStringList to store the
+
  // pour stocker les données de la sortie programme.
// data read from the programs output.
 
 
  var  
 
  var  
 
   AProcess: TProcess;
 
   AProcess: TProcess;
 
   AStringList: TStringList;
 
   AStringList: TStringList;
 
   
 
   
  // This is where our program starts to run
+
  // Le programme commence ici.
 
  begin
 
  begin
   // Now we will create the TProcess object, and
+
   // On créé l'objet TProcess,
   // assign it to the var AProcess.
+
   // et on l'assigne à la variable AProcess
 
   AProcess := TProcess.Create(nil);
 
   AProcess := TProcess.Create(nil);
 
   
 
   
   // Create the TStringList object.
+
   // On créé l'objet TStringList
 
   AStringList := TStringList.Create;
 
   AStringList := TStringList.Create;
 
   
 
   
   // Tell the new AProcess what the command to execute is.
+
   // On dit au nouveau AProcess quelle est la commande à exécuter
   // Let's use the FreePascal compiler
+
   // Utilisons le compilateur de FreePascal
 
   AProcess.CommandLine := 'ppc386 -h';
 
   AProcess.CommandLine := 'ppc386 -h';
 
   
 
   
   // We will define an option for when the program
+
   // Définissons une option pour indiquer que le programme est lancé.
  // is run. This option will make sure that our program
+
   // Cela assurera que notre programme n'attend pas que le programme lancé soit terminé.
  // does not continue until the program we will launch
+
   // Nous allons aussi lui dire que nous voulons lire la sortie du fichier.
   // has stopped running. Also now we will tell it that
 
   // we want to read the output of the file.
 
 
   AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
 
   AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
 
   
 
   
   // Now that AProcess knows what the commandline is
+
   // Maintenent que AProcess sait quelle ligne de commande il doit lancer, go!
  // we will run it.
 
 
   AProcess.Execute;
 
   AProcess.Execute;
 
    
 
    
   // This is not reached until ppc386 stops running.
+
   // Le programme ne va pas plus loin tant que ppc386 n'a pas fini.
 
   
 
   
   // Now read the output of the program we just ran
+
   // Maintenant on lit dans la TStringList la sortie du programme.
  // into the TStringList.
 
 
   AStringList.LoadFromStream(AProcess.Output);
 
   AStringList.LoadFromStream(AProcess.Output);
 
    
 
    
   // Save the output to a file.
+
   // Sauvegarde de la sortie dans un fichier
 
   AStringList.SaveToFile('output.txt');
 
   AStringList.SaveToFile('output.txt');
 
   
 
   
   // Now that the file is saved we can free the
+
   // Maintenant on peut vider la TStringList et le TProcess.
  // TStringList and the TProcess.
 
 
   AStringList.Free;
 
   AStringList.Free;
 
   AProcess.Free;   
 
   AProcess.Free;   

Revision as of 17:04, 26 November 2009

Deutsch (de) English (en) español (es) français (fr) italiano (it) 日本語 (ja) Nederlands (nl) polski (pl) português (pt) русский (ru) slovenčina (sk) 中文(中国大陆)‎ (zh_CN)

Introduction

Il y a différentes manière de lancer un programme externe, mais nous ne nous concentrerons que sur une seule : TProcess.

Si vous utilisez toujours ShellExecute et/ou WinExec sous Delphi, vous devriez utilisez TProcess comme alternative sous FPC/Lazarus (cela fonctionne également si vous l'utilisez sous Linux, car TProcess et multi-plateforme).

Note : FPC/Lazarus supporte ShellExecute et/ou WinExec, mais uniquement sous Win32. Si votre programme est multi-plateforme, utilisez TProcess, c'est la meilleure solution !

SysUtils.ExecuteProcess

La manière la plus simple si vous n'avez pas besoin de pipes ou toute forme de contrôle est d'utiliser simplement SysUtils.ExecuteProcess('/full/path/to/binary',['arg1','arg2']);

TProcess

Vous pouvez utiliser TProcess pour lancer un programme externe à votre application. Le principal intérêt d'utiliser TProcess est qu'il est :

  • Indépendant de la plateforme
  • Capable de lire les entrées sorties standards (stdin, stdout).

Un exemple simple

<pascal>

// This is a demo program that shows how to launch
// an external program.
program launchprogram;

// Here we include files that have useful functions
// and procedures we will need.
uses 
  Classes, SysUtils, Process;

// This is defining the var "AProcess" as a variable 
// of the type "TProcess"
var 
  AProcess: TProcess;

// This is where our program starts to run
begin
  // Now we will create the TProcess object, and
  // assign it to the var AProcess.
  AProcess := TProcess.Create(nil);

  // Tell the new AProcess what the command to execute is.
  // Let's use the FreePascal compiler
  AProcess.CommandLine := 'ppc386 -h';

  // We will define an option for when the program
  // is run. This option will make sure that our program
  // does not continue until the program we will launch
  // has stopped running.                vvvvvvvvvvvvvv
  AProcess.Options := AProcess.Options + [poWaitOnExit];

  // Now that AProcess knows what the commandline is 
  // we will run it.
  AProcess.Execute;

  // This is not reached until ppc386 stops running.
  AProcess.Free;   
end.

</pascal> C'est tout ! Vous venez d'apprendre à lancer un programme externe depuis votre application.

Un exemple amélioré

C'est bien gentil tout ça, mais comment puis je lire la sortie d'un programme que je viens de lancer ?

Bien, étendons juste un peu notre exemple :

<pascal>

// Ceci est un programme de démonstration qui montre
// comment lancer un programme externe et lire sa sortie
program launchprogram;

// Ici on inclue les fichiers qui ont les fonctions et procédures
// dont nous avons besoin
uses 
  Classes, SysUtils, Process;

// Ceci définit la variable "AProcess" comment variable
// de type "TProcess". On ajoute aussi une TStringList
 // pour stocker les données de la sortie programme.
var 
  AProcess: TProcess;
  AStringList: TStringList;

// Le programme commence ici.
begin
  // On créé l'objet TProcess,
  // et on l'assigne à la variable AProcess
  AProcess := TProcess.Create(nil);

  // On créé l'objet TStringList
  AStringList := TStringList.Create;

  // On dit au nouveau AProcess quelle est la commande à exécuter
  // Utilisons le compilateur de FreePascal
  AProcess.CommandLine := 'ppc386 -h';

  // Définissons une option pour indiquer que le programme est lancé.
  // Cela assurera que notre programme n'attend pas que le programme lancé soit terminé.
  // Nous allons aussi lui dire que nous voulons lire la sortie du fichier.
  AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];

  // Maintenent que AProcess sait quelle ligne de commande il doit lancer, go!
  AProcess.Execute;
  
  // Le programme ne va pas plus loin tant que ppc386 n'a pas fini.

  // Maintenant on lit dans la TStringList la sortie du programme.
  AStringList.LoadFromStream(AProcess.Output);
  
  // Sauvegarde de la sortie dans un fichier
  AStringList.SaveToFile('output.txt');

  // Maintenant on peut vider la TStringList et le TProcess.
  AStringList.Free;
  AProcess.Free;   
end.

</pascal>

Lire une grosse sortie

Dans l'exemple précédent, nous attendons que le programme se termine. Au moment de la lecture, le programme à écrit sur la sortie. Mais supposons que le programme écrive beaucoup d'informations en sortie, le canal se saturera et nécessitera une lecture. Mais le programme appelant ne peu rien lire tant que le programme appelé n'est pas terminé. Une étreinte mortelle (deadlock) se produit alors.

Le programme suivant, bien que n'utilisant pas poWaitOnExit, lit tout de même la sortie, tant que le programme est ouvert. La sortie est stockée dans un flux de mémoire, et peut être utilisé plus tard pour lire la sortie dans un TStringList.

<pascal>

program procoutlarge;
{
    Copyright (c) 2004 by Marc Weustink

    This example is creeated in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}

uses
  Classes, Process, SysUtils;

const
  READ_BYTES = 2048;
  
var
  S: TStringList;
  M: TMemoryStream;
  P: TProcess;
  n: LongInt;
  BytesRead: LongInt;

begin
  // We cannot use poWaitOnExit here since we don't
  // know the size of the output. On Linux the size of the
  // output pipe is 2 kB. If the output data is more, we 
  // need to read the data. This isn't possible since we are 
  // waiting. So we get a deadlock here.
  //
  // A temp Memorystream is used to buffer the output
  
  M := TMemoryStream.Create;
  BytesRead := 0;

  P := TProcess.Create(nil);
  P.CommandLine := 'ppc386 -va bogus.pp';
  P.Options := [poUsePipes];
  WriteLn('-- executing --');
  P.Execute;
  while P.Running do
  begin          
    // make sure we have room
    M.SetSize(BytesRead + READ_BYTES);
    
    // try reading it
    n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
    if n > 0 
    then begin
      Inc(BytesRead, n);
      Write('.')
    end
    else begin     
      // no data, wait 100 ms
      Sleep(100); 
    end;
  end;
  // read last part
  repeat
    // make sure we have room
    M.SetSize(BytesRead + READ_BYTES);
    // try reading it
    n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
    if n > 0 
    then begin
      Inc(BytesRead, n);
      Write('.');
    end;
  until n <= 0;
  if BytesRead > 0 then WriteLn;
  M.SetSize(BytesRead); 
  WriteLn('-- executed --');
  
  S := TStringList.Create;
  S.LoadFromStream(M);
  WriteLn('-- linecount = ', S.Count, ' --');
  for n := 0 to S.Count - 1 do
  begin
    WriteLn('| ', S[n]);
  end;
  WriteLn('-- end --');
  S.Free;
  P.Free;
  M.Free;
end.

</pascal>

Employer l'entrée et la sortie d'un TProcess

Voir l'exemple processdemo dans le dépôt SVN de Lazarus-CCR .

Remarque sur l'utilisation de TProcess

Si vous programmez une application multi-plateforme, vous pouvez changer la ligne de commande appelant l'application, en fonction du système d'exploitation. Pour cela utilisez {$IFDEF} et {$ENDIF}.

Exemple : <pascal>

{...}
  AProcess:TProcess.Create(nil)
  {$IFDEF WIN32}
  AProcess.CommandLine := 'calc.exe'; //Windows Calc
  {$ENDIF}
  {$IFDEF LINUX}
  AProcess.CommandLine := 'kcalc'; //KDE Calc
  {$ENDIF}
  AProcess.Execute; //in alternative, you can use AProcess.Active:=True
{...}

</pascal>

Exemple de "Dialogue" avec le processus aspell

Dans le code source de pasdoc pasdoc vous trouverez deux unités qui analysent du texte par "dialogue" en lançant un processus aspell au travers de canaux :

  • PasDoc_ProcessLineTalk.pas unit implémente la classe TProcessLineTalk, descendante de TProcess, qui permet un dialogue facile entre n'importe quel processus sur le principe du ligne par ligne.
  • PasDoc_Aspell.pas units implémente la classe de TAspellProcess, qui permet d'analyser du texte en utilisant l'exemple de TProcessLineTalk pour exécuter aspell et communiquer avec le processus en cours d'exécution d'aspell.

Ces deux unités sont plutôt indépendantes du reste des sources de pasdoc, par conséquent elles peuvent servir d'exemples d'utilisation de TProcess en situation réelle pour exécuter et communiquer par les canaux avec un autre programme.