从Windows XP的Delphi应用程序中的命令行程序获取输出 [英] Getting output from a command-line program in a Delphi application on Windows XP

查看:95
本文介绍了从Windows XP的Delphi应用程序中的命令行程序获取输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有用Delphi XE2编写的VCL应用程序,该应用程序需要执行命令行程序(也用Delphi XE2编写),并获取其输出的文本。我当前正在使用以下代码,该代码基于此处的代码:将shell / dos应用程序中的输出输出到Delphi应用程序中

I have VCL application written in Delphi XE2 that needs to execute a command-line program (also written in Delphi XE2) and obtain the text output by it. I am currently using the following code, which is based on that found here: 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应用程序,那么命令行程序 then 似乎已成功完成其工作(事实证明该程序输出了我期望的文件)。我还注意到,如果我从StartupInfo.dwFlags中删除STARTF_USESTDHANDLES,则命令行程序将正常运行,并且WaitForSingleObject会立即返回。但是,我显然无法获得程序返回的文本。

This works fine on most versions of Windows. Unfortunately it has recently come to our attention that it does not work on Windows XP. The call to WaitForSingleObject simply never returns. I tried replacing the second parameter INFINITE with a smaller value (e.g. 15000) but that doesnt't seem to make any difference. In Task Manager I can see that, after calling GetDosOutput, the command-line program is actually running. If I end the VCL application, the command-line program then seems to complete its work successfully (as evidenced by the fact that it outputs the files I was expecting it to). I've also noticed that if I remove STARTF_USESTDHANDLES from StartupInfo.dwFlags, the command-line program runs normally and WaitForSingleObject returns promptly; however I am then obviously unable to obtain the text returned by the program.

有人对我如何在Windows XP上运行它提出建议吗?

Does anybody have a suggestion as to how I can get this working on Windows XP?

推荐答案

在freepascal中有一个非常有用的单元称为 process,它可以完成此工作,并且已经完成了端口到Delphi ,因此您可以使用一个简单的划线器在 Delphi 中捕获命令的输出:

There is a really useful unit in freepascal called "process", which does just that, and, work has been done to port it to Delphi so you can capture the output of a command in Delphi using a simple one liner:

RunCommand()

或者您可以通过创建更高级的功能来捕获命令的输出

Or you can capture the output of the command with more advanced features by creating a TProcess object yourself (which RunCommand just wraps).

项目在这里:

  • https://github.com/z505/TProcess-Delphi
  • A simple demo: https://github.com/z505/TProcess-Delphi/tree/master/demo-simple

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

How to capture the output of a command, i.e. "dir" (list directory contents, famous MS DOS command) into a string then add it to a memo:

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

这篇关于从Windows XP的Delphi应用程序中的命令行程序获取输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆