4

短い Pascal プログラム内からいくつかの Windows コマンド ライン ツールを使用しようとしています。簡単にするために、コマンド ライン文字列を引数として受け取り、プロセスの終了コード用の 1 つのフィールドとプロセスの出力テキスト用の 1 つのフィールドを持つ、ShellResult というレコード タイプを返す DoShell という関数を作成しています。

一部の標準ライブラリ関数が期待どおりに機能しないという大きな問題があります。DOS Exec() 関数は、私が渡したコマンドを実際には実行していません。コンパイラ モード {I-} を設定しない限り、Reset() プロシージャで実行時エラー RunError(2) が発生します。その場合、実行時エラーは発生しませんが、後でそのファイルで使用する Readln() 関数は実際には何も読み取らず、さらにコード実行のその時点以降に使用される Writeln() 関数も何もしません。

これまでの私のプログラムのソースコードです。私は Lazarus 0.9.28.2 beta と Free Pascal Compiler 2.24 を使用しています。


program project1;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, StrUtils, Dos
  { you can add units after this };

{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF}

type
  ShellResult = record
    output    : AnsiString;
    exitcode  : Integer;
  end;

function DoShell(command: AnsiString): ShellResult;
    var
      exitcode: Integer;
      output: AnsiString;
      exepath: AnsiString;
      exeargs: AnsiString;
      splitat: Integer;
      F: Text;
      readbuffer: AnsiString;
    begin
      //Initialize variables
      exitcode   := 0;
      output     := '';
      exepath    := '';
      exeargs    := '';
      splitat    := 0;
      readbuffer := '';
      Result.exitcode := 0;
      Result.output   := '';

      //Split command for processing
      splitat := NPos(' ', command, 1);
      exepath := Copy(command, 1, Pred(splitat));
      exeargs := Copy(command, Succ(splitat), Length(command));

      //Run command and put output in temporary file
      Exec(FExpand(exepath), exeargs + ' >__output');
      exitcode := DosExitCode();

      //Get output from file
      Assign(F, '__output');
      Reset(F);
      Repeat
        Readln(F, readbuffer);
        output := output + readbuffer;
        readbuffer := '';
      Until Eof(F);

      //Set Result
      Result.exitcode := exitcode;
      Result.output   := output;

    end;

var
  I : AnsiString;
  R : ShellResult;
begin
  Writeln('Enter a command line to run.');
  Readln(I);
  R := DoShell(I);
  Writeln('Command Exit Code:');
  Writeln(R.exitcode);
  Writeln('Command Output:');
  Writeln(R.output);
end.
4

3 に答える 3

1

dos.exec は使用しないでください。短い (255 文字) コマンド ラインに制限されています。を使用しsysutils.executeprocessます。

しかし、Michal のコメントはおそらく主要な問題に触れています。カーネル (シェルではない) 関数を介して実行する場合は、常に完全なパスを提供する必要があります。また、カーネル関数を使用すると、リダイレクトなどのシェル コマンドを使用できません。

TProcess一般に、単元でクラスを使用することをお勧めしますprocess。これらすべてを抽象化し、Lazarus が外部ツールを呼び出すためにも使用します。

于 2010-05-10T14:31:29.017 に答える
1

あなたはそれを使うことができます:

uses sysutils;

begin
    ExecuteProcess('cmd','/c dir C:\foo');
    ExecuteProcess('C:\foo\bar.exe','param1 param2');
end.

コマンドの出力を取得したい場合は、この投稿を参照してください。http://wiki.freepascal.org/Executing_External_Programs#TProcess

于 2013-11-26T14:49:41.247 に答える
1

ざっと見てみると、スペースに基づいてコマンドを分割しようとしていることがわかります。仮に:

  • fpc?のように、パラメータなしで何かを実行しようとしました。(回答: exepath は空になります)
  • フルパスとその中にスペースを入れて何かを実行しようとしましたC:\Program Files\Edit Plus 3\editplus.exeか?

試しExec()てみたところ、実行したい実行可能ファイルへのフルパスを指定するとうまくいくようですが、出力のリダイレクトはうまくいきません。見てください:コマンドラインリダイレクトはコマンドラインインタープリターによって実行されます。ただし、リダイレクトを行うファイルを実行することはでき.batます (ユーザーが与えるコマンド + リダイレクトで一時.batファイルを作成し、そのバッチを実行します)。

于 2010-05-07T08:18:46.080 に答える