Difference between revisions of "Executing External Programs/ja"

From Lazarus wiki
Jump to navigationJump to search
 
Line 50: Line 50:
 
これで自分のプログラムから、外部のプログラムを走らせる方法がわかりますね。
 
これで自分のプログラムから、外部のプログラムを走らせる方法がわかりますね。
  
===An Improved Example===
+
===より向上した見本===
That's nice, but how do I read the Output of a program that I have run?
+
いいですね、では自分では知らせたプログラムの出力を読むにはどうしたら良いでしょう?
  
Well, let's expand our example a little and do just that:
+
では先ほどの例を改良して、それをやってみましょう。
  
  // This is a demo program that shows how to launch
+
  // これはいかにして外部プログラムを走らせて、その出力を読むか
  // an external program and read from it's output.
+
  // 示したデモプログラムです。
 
  program launchprogram;
 
  program launchprogram;
 
   
 
   
  // Here we include files that have useful functions
+
  // ここで関数や手続き使用するために
  // and procedures we will need.
+
  // ファイルをインクルードしておきます
 
  uses  
 
  uses  
 
   Classes, SysUtils, Process;
 
   Classes, SysUtils, Process;
Line 72: Line 72:
 
   AStringList: TStringList;
 
   AStringList: TStringList;
 
   
 
   
  // This is where our program starts to run
+
  // ここからプログラムが走ります
 
  begin
 
  begin
   // Now we will create the TProcess object, and
+
   // TProcessオブジェクトを生成します
   // assign it to the var AProcess.
+
   // そしてそれを変数AProcessにアサインします
 
   AProcess := TProcess.Create(nil);
 
   AProcess := TProcess.Create(nil);
 
   
 
   
   // Create the TStringList object.
+
   // TStringListオブジェクトを生成します
 
   AStringList := TStringList.Create;
 
   AStringList := TStringList.Create;
 
   
 
   
   // Tell the new AProcess what the command to execute is.
+
   // AProcessに実行するコマンドを伝えます
   // Let's use the FreePascal compiler
+
   // FreePascalコンパイラを走らせてみます
 
   AProcess.CommandLine := 'ppc386 -h';
 
   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];
 
   AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
 
   
 
   
   // Now that AProcess knows what the commandline is
+
   // AProcessはコマンドライン上で実行されるように実行されます
  // we will run it.
 
 
   AProcess.Execute;
 
   AProcess.Execute;
 
    
 
    
   // This is not reached until ppc386 stops running.
+
   // ppc386が停止するまで、次にいきません
 
   
 
   
   // Now read the output of the program we just ran
+
   // ここでTStringListに出力を読み込みます。
  // into the TStringList.
 
 
   AStringList.LoadFromStream(AProcess.Output);
 
   AStringList.LoadFromStream(AProcess.Output);
 
    
 
    
   // Save the output to a file.
+
   // ファイルに保存します
 
   AStringList.SaveToFile('output.txt');
 
   AStringList.SaveToFile('output.txt');
 
   
 
   
   // Now that the file is saved we can free the
+
   // 保存が完了したので
   // TStringList and the TProcess.
+
   // TStringListとTProcessを開放します
 
   AStringList.Free;
 
   AStringList.Free;
 
   AProcess.Free;   
 
   AProcess.Free;   

Revision as of 11:09, 4 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)

概要

外部のプログラムを動かすにはいくつかの方法がありますが、このチュートリアルではTProcessに限定して紹介しています。

TProcess

あなたはTProcessを使って外部プログラムを走らせることができます。TProcessを使用することによるメリットは次の通りです。

  • プラットホーム非依存
  • stdinからの読み込み、stdoutへの書き込みが可能

単純な見本

// これは外部プログラムを走らせてみる、デモプログラムです
program launchprogram;

// ここで関数や手続き使用するために
// ファイルをインクルードしておきます
uses 
  Classes, SysUtils, Process;

// "TProcess"型の"AProcess"
// という変数を定義しておきます

var 
  AProcess: TProcess;

// ここからプログラムが走ります
begin
  // TProcessオブジェクトを生成します
  // そしてそれを変数AProcessにアサインします
  AProcess := TProcess.Create(nil);

  // AProcessに実行するコマンドを伝えます
  // FreePascalコンパイラを走らせてみます
  AProcess.CommandLine := 'ppc386 -h';

  // ここでプログラムを走らせるときの、オプションを定義します
  // このオプションは、自分のプログラムを走らせたプログラムが
  // 停止するまで動かないようにします         vvvvvvvvvvvvvv
  AProcess.Options := AProcess.Options + [poWaitOnExit];

  // ここでAProcessが走ります。
  AProcess.Execute;

  // ppc386が停止するまで、これは実行されません。
  AProcess.Free;   
end.

これで自分のプログラムから、外部のプログラムを走らせる方法がわかりますね。

より向上した見本

いいですね、では自分では知らせたプログラムの出力を読むにはどうしたら良いでしょう?

では先ほどの例を改良して、それをやってみましょう。

// これはいかにして外部プログラムを走らせて、その出力を読むか
// 示したデモプログラムです。
program launchprogram;

// ここで関数や手続き使用するために
// ファイルをインクルードしておきます
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;

// ここからプログラムが走ります
begin
  // TProcessオブジェクトを生成します
  // そしてそれを変数AProcessにアサインします
  AProcess := TProcess.Create(nil);

  // TStringListオブジェクトを生成します
  AStringList := TStringList.Create;

  // AProcessに実行するコマンドを伝えます
  // FreePascalコンパイラを走らせてみます
  AProcess.CommandLine := 'ppc386 -h';

  // ここでプログラムを走らせるときの、オプションを定義します
  // このオプションは、自分のプログラムを走らせたプログラムが
  // 停止するまで動かないようにします

  // また、ファイルの出力を読めるようにします

  AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];

  // AProcessはコマンドライン上で実行されるように実行されます
  AProcess.Execute;
  
  // ppc386が停止するまで、次にいきません

  // ここでTStringListに出力を読み込みます。
  AStringList.LoadFromStream(AProcess.Output);
  
  // ファイルに保存します
  AStringList.SaveToFile('output.txt');

  // 保存が完了したので
  // TStringListと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
  // 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.

Example of "talking" with aspell process

Inside pasdoc source code you can find two units that perform spell-checking by "talking" with running aspell process through pipes:

  • 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.
  • 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.

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.