Difference between revisions of "Executing External Programs/ja"

From Free Pascal wiki
Jump to navigationJump to search
Line 6: Line 6:
  
 
外部のプログラムを動かすにはいくつかの方法がありますが、このチュートリアルではTProcessに限定して紹介しています。
 
外部のプログラムを動かすにはいくつかの方法がありますが、このチュートリアルではTProcessに限定して紹介しています。
 +
 +
Delphiで ShellExecute や WinExec を使っていたなら、 TProcessがFPC/Lazarusにおける代替となります。(TProcess は cross-platformであり、Linuxでも有効です。)
 +
 +
Note: FPC/Lazarus は ShellExecute 及び WinExec をサポートしていますが、WIn32のみで有効です。 あなたのプログラムが cross-platformを目標にしているなら、TProcessの使用が最善です!
  
 
==TProcess==
 
==TProcess==

Revision as of 10:09, 23 June 2008

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)

日本語版メニュー
メインページ - Lazarus Documentation日本語版 - 翻訳ノート - 日本語障害情報

概要

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

Delphiで ShellExecute や WinExec を使っていたなら、 TProcessがFPC/Lazarusにおける代替となります。(TProcess は cross-platformであり、Linuxでも有効です。)

Note: FPC/Lazarus は ShellExecute 及び WinExec をサポートしていますが、WIn32のみで有効です。 あなたのプログラムが cross-platformを目標にしているなら、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.

巨大な出力を読み取る

いままでの見本では、プログラムの終了まで待って、既に書き終えた出力をその後に読み取っていました。でもプログラムが大量の出力を行う場合、パイプを通じて読み取る必要があります。しかし、呼ばれたプログラムが終わるまで、プログラムから読むことができません。

この見本ではpoWaitOnExitを使わず、プログラムの実行中に出力をメモリストリームに入れていきます。それを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
  // poWaintOnExitを使うことはできませんので
  // 出力のサイズがわかりません。
  // Linuxにおいては出力パイプの大きさが2kbです。
  // これ以上の大きさのデータを読むことはこの方法ではできません。
  // 従って行き詰まります。
  //
  // Memorystreamは出力バッファとして使います。
  
  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          
    // メモリ空間を確保します
    M.SetSize(BytesRead + READ_BYTES);
    
    // 読んでいきます
    n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
    if n > 0 
    then begin
      Inc(BytesRead, n);
      Write('.')
    end
    else begin     
      // データがないときは100 ms待ちます
      Sleep(100); 
    end;
  end;
  // 読み込みの最終段階です
  repeat
    // メモリ空間を確保します
    M.SetSize(BytesRead + READ_BYTES);
    // 読んでいきます
    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.

aspellによる"talking"の見本

pasdoc ソースコードではあなたはふたつのユニットを発見し、aspellプロセスを実行しパイプを介してスペルチェックを"talking"によって行っています。

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