Difference between revisions of "Executing External Programs/fr"

From Free Pascal wiki
Jump to navigationJump to search
Line 223: Line 223:
  
 
Exemple :
 
Exemple :
 +
<pascal>
 
  {...}
 
  {...}
 
   AProcess:TProcess.Create(nil)
 
   AProcess:TProcess.Create(nil)
Line 233: Line 234:
 
   AProcess.Execute; //in alternative, you can use AProcess.Active:=True
 
   AProcess.Execute; //in alternative, you can use AProcess.Active:=True
 
  {...}
 
  {...}
 +
</pascal>
  
 
=== Exemple de "Dialogue" avec le processus aspell ===
 
=== Exemple de "Dialogue" avec le processus aspell ===

Revision as of 22:20, 4 July 2007

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>

// This is a demo program that shows how to launch
// an external program and read from it's output.
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"
// Also now we are adding a TStringList to store the 
// data read from the programs output.
var 
  AProcess: TProcess;
  AStringList: TStringList;

// 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);

  // Create the TStringList object.
  AStringList := TStringList.Create;

  // 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. Also now we will tell it that
  // we want to read the output of the file.
  AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];

  // Now that AProcess knows what the commandline is 
  // we will run it.
  AProcess.Execute;
  
  // This is not reached until ppc386 stops running.

  // Now read the output of the program we just ran
  // into the TStringList.
  AStringList.LoadFromStream(AProcess.Output);
  
  // Save the output to a file.
  AStringList.SaveToFile('output.txt');

  // Now that the file is saved we can free the 
  // TStringList and the 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.