简体   繁体   English

Delphi XE8:运行外部控制台应用程序,等待其结果并捕获其结果时出现问题

[英]Delphi XE8: problems running an external console application, waiting for its results and capturing its results

In Delphi XE8 under Windows, I am trying to call an external console application and capture its output. 在Windows下的Delphi XE8中,我试图调用一个外部控制台应用程序并捕获其输出。 I use the following code, as described in Capture the output from a DOS (command/console) Window and also Getting output from a shell/dos app into a Delphi app : 我使用以下代码,如从DOS(命令/控制台)窗口捕获输出以及从Shell / DOS应用程序将输出获取到Delphi应用程序中所述

procedure TForm1.Button1Click(Sender: TObject) ;

  procedure RunDosInMemo(DosApp:String;AMemo:TMemo) ;
  const
    ReadBuffer = 2400;
  var
    Security : TSecurityAttributes;
    ReadPipe,WritePipe : THandle;
    start : TStartUpInfo;
    ProcessInfo : TProcessInformation;
    Buffer : Pchar;
    BytesRead : DWord;
    Apprunning : DWord;
    S: String;
  begin
    With Security do begin
      nlength := SizeOf(TSecurityAttributes) ;
      binherithandle := true;
      lpsecuritydescriptor := nil;
    end;
    if Createpipe (ReadPipe, WritePipe,
                   @Security, 0) then 
    begin
      Buffer := AllocMem(ReadBuffer + 1) ;
      FillChar(Start,Sizeof(Start),#0) ;
      start.cb := SizeOf(start) ;
      start.hStdOutput := WritePipe;
      start.hStdInput := ReadPipe;
      start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
      start.wShowWindow := SW_HIDE;

      S:=UniqueString(DosApp);
      if CreateProcess(nil,
              PChar(S),
              @Security,
              @Security,
              true,
              NORMAL_PRIORITY_CLASS,
              nil,
              nil,
              start,
              ProcessInfo) then
      begin
        repeat
          Apprunning := WaitForSingleObject
                        (ProcessInfo.hProcess,100) ;
          Application.ProcessMessages;
        until (Apprunning <> WAIT_TIMEOUT) ;
        Repeat
          BytesRead := 0;
          ReadFile(ReadPipe,Buffer[0], ReadBuffer,BytesRead,nil) ;
          Buffer[BytesRead]:= #0;
          OemToAnsi(Buffer,Buffer) ;
          AMemo.Text := AMemo.text + String(Buffer) ;
        until (BytesRead < ReadBuffer) ;
      end;
      FreeMem(Buffer) ;
      CloseHandle(ProcessInfo.hProcess) ;
      CloseHandle(ProcessInfo.hThread) ;
      CloseHandle(ReadPipe) ;
      CloseHandle(WritePipe) ;
    end;
  end;

begin {button 1 code}
  RunDosInMemo('cmd.exe /c dir',Memo1) ; //<-- this works
  RunDosInMemo('"c:\consoleapp.exe" "/parameter"',Memo1) //<-- this hangs in the repeat until (Apprunning <> WAIT_TIMEOUT) ; 
end;

It works for DOS commands, but it does not work for a console application. 它适用于DOS命令,但不适用于控制台应用程序。 The console application starts and executes correctly but it hangs in the repeat until (Apprunning <> WAIT_TIMEOUT) loop. 控制台应用程序将启动并正确执行,但会repeat until (Apprunning <> WAIT_TIMEOUT)挂起, repeat until (Apprunning <> WAIT_TIMEOUT)循环repeat until (Apprunning <> WAIT_TIMEOUT) What could I try to solve the problem? 我可以尝试解决什么问题?

Thank you very much! 非常感谢你!

The program you're running is either expecting input (like from the keyboard) or producing more output than will fit in the pipe's buffer. 您正在运行的程序期望输入(例如从键盘输入)或产生比管道缓冲区适合的输出更多的输出。 In either case, that program hangs waiting for further I/O operations, but your parent program is waiting for that child to terminate before processing any output, and never provides any input. 无论哪种情况,该程序都会挂起,等待进一步的I / O操作,但是您的父程序正在等待该子项终止,然后再处理任何输出,并且从不提供任何输入。

You need to process the output pipe while the program is still running. 您需要在程序仍在运行时处理输出管道。 Otherwise, you risk the buffer filling up, and the child will block until more space becomes available. 否则,您可能会冒缓冲区被填满的风险,并且孩子将阻塞直到有更多空间可用为止。 Likewise, if you don't plan to provide any input to the other process, you probably shouldn't give it a valid input handle. 同样,如果您不打算向其他进程提供任何输入,则可能不应该为其提供有效的输入句柄。 That way, if it tries to read input, it will fail, rather than block. 这样,如果它尝试读取输入,它将失败而不是阻塞。

Furthermore, the input handle you've given to that program is attached to the output handle. 此外,您为该程序指定的输入句柄将附加到输出句柄。 If the program attempts to read, it will be reading its own output, like an I/O ouroboros. 如果程序尝试读取,它将读取自己的输出,例如I / O拾音器。 To handle input and output, you need two pipes. 要处理输入输出,您需要两个管道。

(Note that this deadlock is exactly the problem I called out in the comments of the answer you used . The second code block in the same answer addresses the problem, as well as the ouroboros problem.) (请注意,此死锁正是我在您所使用的答案的注释中提到的问题。同一答案中的第二个代码块解决了该问题以及我们的风衣蛇问题。)

To summarize: @David Heffernan's code in Execute DOS program and get output dynamically works. 总结一下:@David Heffernan在Execute DOS程序中的代码并动态获取输出 The problem is that the console application emits UTF-16. 问题是控制台应用程序发出UTF-16。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM