Difference between revisions of "Executing External Programs/de"

From Lazarus wiki
Jump to navigationJump to search
m
Line 12: Line 12:
  
 
===Ein einfaches Beispiel===
 
===Ein einfaches Beispiel===
  // This is a demo program that shows how to launch
+
  // Dies ist ein Demoprogramm das zeigt wie man ein
  // an external program.
+
  // externes Programm startet.
 
  program launchprogram;
 
  program launchprogram;
 
   
 
   
Line 21: Line 21:
 
   Classes, SysUtils, Process;
 
   Classes, SysUtils, Process;
 
   
 
   
  // This is defining the var "AProcess" as a variable
+
  // Dies definiert die Variable "AProcess" als eine Variable
  // of the type "TProcess"
+
  // vom Typ "TProcess"
 
  var  
 
  var  
 
   AProcess: TProcess;
 
   AProcess: TProcess;
Line 55: Line 55:
  
 
===Ein verbessertes Beispiel===
 
===Ein verbessertes Beispiel===
That's nice, but how do I read the Output of a program that I have run?
+
Das ist nett, aber wie lese ich den Output von einem Programm, das I have run?
  
Well, let's expand our example a little and do just that:
+
Lassen sie uns unser Beispiel ein wenig erweitern und einfach das tun:
  
 
  // This is a demo program that shows how to launch
 
  // This is a demo program that shows how to launch
Line 86: Line 86:
 
   
 
   
 
   // Tell the new AProcess what the command to execute is.
 
   // Tell the new AProcess what the command to execute is.
   // Let's use the FreePascal compiler
+
   // Lassen sie uns den FreePascal Compiler verwenden
 
   AProcess.CommandLine := 'ppc386 -h';
 
   AProcess.CommandLine := 'ppc386 -h';
 
   
 
   
Line 106: Line 106:
 
   AStringList.LoadFromStream(AProcess.Output);
 
   AStringList.LoadFromStream(AProcess.Output);
 
    
 
    
   // Save the output to a file.
+
   // Speichert den output in eine Datei.
 
   AStringList.SaveToFile('output.txt');
 
   AStringList.SaveToFile('output.txt');
 
   
 
   
Line 115: Line 115:
 
  end.
 
  end.
  
===Reading large output===
+
=== Reading large output ===
 
In the previous example we waited until the program exited. Then we read, what the program has written to its output. But suppose the program writes a lot of data to the output, the pipe becomes full and needs to read. But the calling program doesn't read from it, until the called program has ended. A dead lock occurs.
 
In the previous example we waited until the program exited. Then we read, what the program has written to its output. But suppose the program writes a lot of data to the output, the pipe becomes full and needs to read. But the calling program doesn't read from it, until the called program has ended. A dead lock occurs.
  
Line 143: Line 143:
 
   
 
   
 
  begin
 
  begin
   // We cannot use poWaitOnExit here since we don't
+
   // Wir können poWaitOnExit hier nicht nutzen weil wir
   // know the size of the output. On Linux the size of the
+
   // die Größe des Outputs nicht kennen. On Linux the size of the
 
   // output pipe is 2 kB. If the output data is more, we  
 
   // output pipe is 2 kB. If the output data is more, we  
 
   // need to read the data. This isn't possible since we are  
 
   // need to read the data. This isn't possible since we are  
Line 161: Line 161:
 
   while P.Running do
 
   while P.Running do
 
   begin           
 
   begin           
     // make sure we have room
+
     // stellt sicher daß wir Platz haben
 
     M.SetSize(BytesRead + READ_BYTES);
 
     M.SetSize(BytesRead + READ_BYTES);
 
      
 
      
     // try reading it
+
     // versuche es zu lesen
 
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
 
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
 
     if n > 0  
 
     if n > 0  
Line 172: Line 172:
 
     end
 
     end
 
     else begin     
 
     else begin     
       // no data, wait 100 ms
+
       // keine Daten, warte 100 ms
 
       Sleep(100);  
 
       Sleep(100);  
 
     end;
 
     end;
 
   end;
 
   end;
   // read last part
+
   // lese den letzten Teil
 
   repeat
 
   repeat
     // make sure we have room
+
     // stellt sicher daß wir Platz haben
 
     M.SetSize(BytesRead + READ_BYTES);
 
     M.SetSize(BytesRead + READ_BYTES);
     // try reading it
+
     // versuche es zu lesen
 
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
 
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
 
     if n > 0  
 
     if n > 0  
Line 205: Line 205:
 
  end.
 
  end.
  
=== Example of "talking" with aspell process ===
+
=== Beispiel von "talking" mit dem aspell Prozess ===
  
Inside [http://pasdoc.sourceforge.net/ pasdoc] source code you can find two units that perform spell-checking by "talking" with running aspell process through pipes:
+
Innerhalb des [http://pasdoc.sourceforge.net/ pasdoc] Quellcodes können sie zwei Units finden that perform spell-checking by "talking" with running aspell process through pipes:
  
* [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_ProcessLineTalk.pas PasDoc_ProcessLineTalk.pas unit] implements TProcessLineTalk class, descendant of TProcess, that can be easily used to talk with any process on a line-by-line basis.
+
* [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_ProcessLineTalk.pas PasDoc_ProcessLineTalk.pas unit] implementiert die TProcessLineTalk Klasse, einen Nachfahren von TProcess, der einfach benutzt werden kann to talk with any process on a line-by-line basis.
  
* [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_Aspell.pas PasDoc_Aspell.pas units] implements TAspellProcess class, that performs spell-checking by using underlying TProcessLineTalk instance to execute aspell and communicate with running aspell process.
+
* [http://cvs.sourceforge.net/viewcvs.py/*checkout*/pasdoc/pasdoc/source/component/PasDoc_Aspell.pas PasDoc_Aspell.pas units] implementiert die TAspellProcess Klasse, that performs spell-checking by using underlying TProcessLineTalk instance to execute aspell and communicate with running aspell process.
  
Both units are rather independent from the rest of pasdoc sources, so they may serve as real-world examples of using TProcess to run and communicate through pipes with other program.
+
Beide Units sind ziemlich unabhängig vom Rest der pasdoc Quellen, so they may serve as real-world examples of using TProcess to run and communicate through pipes with other program.

Revision as of 19:53, 13 April 2006

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)

Einleitung

Es gibt verschiedene Wege, ein externes Programm auszuführen, aber ich will mich hier auf einen konzentrieren. TProcess.

TProcess

Man kann TProcess benutzen um externe Programme zu starten. Vorteile von TProcess sind

  • Plattform unabhängig
  • Capable of reading from stdout and writing to stdin.

Ein einfaches Beispiel

// Dies ist ein Demoprogramm das zeigt wie man ein
// externes Programm startet.
program launchprogram;

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

// Dies definiert die Variable "AProcess" als eine Variable 
// vom Typ "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.

Das war's. Du hast gerade gelernt, wie man in deinem Programm ein externes Programm aufruft.


Ein verbessertes Beispiel

Das ist nett, aber wie lese ich den Output von einem Programm, das I have run?

Lassen sie uns unser Beispiel ein wenig erweitern und einfach das tun:

// 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.
  // Lassen sie uns den FreePascal Compiler verwenden
  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);
  
  // Speichert den output in eine Datei.
  AStringList.SaveToFile('output.txt');

  // Now that the file is saved we can free the 
  // TStringList and the TProcess.
  AStringList.Free;
  AProcess.Free;   
end.

Reading large output

In the previous example we waited until the program exited. Then we read, what the program has written to its output. But suppose the program writes a lot of data to the output, the pipe becomes full and needs to read. But the calling program doesn't read from it, until the called program has ended. A dead lock occurs.

The following example therefore doesn't use poWaitOnExit, but reads from the output, while the program is still running. The output is stored in a memory stream, that can be used later to read the output into a TStringList.

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
  // Wir können poWaitOnExit hier nicht nutzen weil wir
  // die Größe des Outputs nicht kennen. 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          
    // stellt sicher daß wir Platz haben
    M.SetSize(BytesRead + READ_BYTES);
    
    // versuche es zu lesen
    n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
    if n > 0 
    then begin
      Inc(BytesRead, n);
      Write('.')
    end
    else begin     
      // keine Daten, warte 100 ms
      Sleep(100); 
    end;
  end;
  // lese den letzten Teil
  repeat
    // stellt sicher daß wir Platz haben
    M.SetSize(BytesRead + READ_BYTES);
    // versuche es zu lesen
    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.

Beispiel von "talking" mit dem aspell Prozess

Innerhalb des pasdoc Quellcodes können sie zwei Units finden that perform spell-checking by "talking" with running aspell process through pipes:

  • PasDoc_ProcessLineTalk.pas unit implementiert die TProcessLineTalk Klasse, einen Nachfahren von TProcess, der einfach benutzt werden kann to talk with any process on a line-by-line basis.
  • PasDoc_Aspell.pas units implementiert die TAspellProcess Klasse, that performs spell-checking by using underlying TProcessLineTalk instance to execute aspell and communicate with running aspell process.

Beide Units sind ziemlich unabhängig vom Rest der pasdoc Quellen, so they may serve as real-world examples of using TProcess to run and communicate through pipes with other program.