【问题标题】:Using windows command line from Pascal从 Pascal 使用 windows 命令行
【发布时间】:2011-02-15 06:25:08
【问题描述】:

我正在尝试在一个简短的 Pascal 程序中使用一些 Windows 命令行工具。为了方便起见,我正在编写一个名为 DoShell 的函数,它接受一个命令行字符串作为参数并返回一个名为 ShellResult 的记录类型,其中一个字段用于进程的退出代码,一个字段用于进程的输出文本。

我遇到了一些标准库函数无法按预期工作的重大问题。 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.

【问题讨论】:

  • windows下试试cmd /s programname param1 param2 ...

标签: pascal lazarus freepascal


【解决方案1】:

快速浏览一下,我发现您尝试根据空间拆分命令。如果:

  • 我尝试执行不带参数的操作,例如fpc? (答案:exepath 将为空)
  • 我尝试使用完整路径和空格执行某些操作,例如 C:\Program Files\Edit Plus 3\editplus.exe?

我尝试了Exec(),当您为其提供要运行的可执行文件的完整路径时,它似乎可以工作,但输出重定向不起作用。看:Command line redirection is performed by the command line interpreter。但是,您可以执行执行重定向的 .bat 文件(使用命令用户给出 + 重定向创建临时的 .bat 文件,然后运行该批处理)。

【讨论】:

  • 这就是为什么 sysutils.executeprocess(以 const 数组作为参数)在 2004 年被引入,而 dos.exec 从那时起就被弃用了
【解决方案2】:

不要使用 dos.exec,它仅限于短(255 个字符)命令行。使用sysutils.executeprocess

但是,Michal 的 cmets 可能触及主要问题。通过内核(而非 shell)函数执行时,应始终提供完整路径。此外,使用内核函数不能使用重定向等 shell 命令。

一般来说,我建议你尝试在process 单元中使用TProcess 类。它抽象了所有这些以及更多内容,Lazarus 也使用它来调用外部工具。

【讨论】:

  • 在最近的版本中,单元进程具有运行和捕获输出的 runco​​mmand 函数。
【解决方案3】:

你可以使用它:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-14
    • 2012-08-31
    • 2016-08-13
    相关资源
    最近更新 更多