从Windows XP上的Delphi应用程序中获取命令行程序的输出

时间:2013-09-26 04:58:24

标签: delphi command-line windows-xp

我有用Delphi XE2编写的VCL应用程序,需要执行命令行程序(也用Delphi XE2编写)并获取它的文本输出。我目前正在使用以下代码,该代码基于此处的代码:Getting output from a shell/dos app into a Delphi app

function GetDosOutput(ACommandLine : string; AWorkingDirectory : string): string;
var
  SecurityAttributes : TSecurityAttributes;
  StartupInfo : TStartupInfo;
  ProcessInformation: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..255] of AnsiChar;
  BytesRead: Cardinal;
  Handle: Boolean;
begin
  Result := '';
  SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
  SecurityAttributes.bInheritHandle := True;
  SecurityAttributes.lpSecurityDescriptor := nil;
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SecurityAttributes, 0);
  try
    FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
    StartupInfo.cb := SizeOf(TStartupInfo);
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    StartupInfo.wShowWindow := SW_HIDE;
    StartupInfo.hStdInput := StdOutPipeRead;
    StartupInfo.hStdOutput := StdOutPipeWrite;
    StartupInfo.hStdError := StdOutPipeWrite;
    FillChar(ProcessInformation, SizeOf(ProcessInformation), 0);
    Handle := CreateProcess(
      nil,
      PChar(ACommandLine),
      nil,
      nil,
      True,
      0,
      nil,
      PChar(AWorkingDirectory),
      StartupInfo,
      ProcessInformation
    );
    CloseHandle(StdOutPipeWrite);
    if Handle then
      try
        repeat
          WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
          if BytesRead > 0 then
          begin
            Buffer[BytesRead] := #0;
            Result := Result + Buffer;
          end;
        until not WasOK or (BytesRead = 0);
        WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
      finally
        CloseHandle(ProcessInformation.hThread);
        CloseHandle(ProcessInformation.hProcess);
      end;
  finally
    CloseHandle(StdOutPipeRead);
  end;
end;

这适用于大多数Windows版本。不幸的是,最近我们注意到它在Windows XP上不起作用。对WaitForSingleObject的调用根本不会返回。我尝试用较小的值(例如15000)替换第二个参数INFINITE,但这似乎没有任何区别。在任务管理器中,我可以看到,在调用GetDosOutput之后,命令行程序实际上正在运行。如果我结束VCL应用程序,命令行程序然后似乎成功完成其工作(由它输出我期望它的文件的事实证明)。我还注意到,如果从StartupInfo.dwFlags中删除STARTF_USESTDHANDLES,命令行程序将正常运行并且WaitForSingleObject会立即返回;但是我显然无法获得该程序返回的文本。

是否有人建议我如何在Windows XP上运行?

1 个答案:

答案 0 :(得分:3)

freepascal中有一个非常有用的单元叫做“process”,就是这样,并且已经完成端口到Delphi 的工作所以你可以捕获 Delphi 中的命令输出使用简单的一行:

RunCommand()

或者您可以通过自己创建一个TProcess对象(RunCommand只是包装)来捕获具有更多高级功能的命令输出。

项目在这里:

如何将命令的输出,即“dir”(列出目录内容,着名的MS DOS命令)捕获到字符串中,然后将其添加到备忘录中:

uses 
  dprocess; 
// ...
var 
  output: ansistring;
begin
  RunCommand('cmd', ['/c', 'dir'], output, [poNoConsole]);
  memo1.Lines.Add(output);
end;