【问题标题】:How to read error running Console Application from Delphi Code using PeekNamedPipe()如何使用 PeekNamedPipe() 从 Delphi 代码中读取运行控制台应用程序的错误
【发布时间】:2014-07-01 11:28:35
【问题描述】:

我有 Delphi 代码,用于从 JAVA_HOME 运行 Java.exe,并带有一组给定的参数。这是通过 CreateProcess() 通过将命令行命令传递给它来实现的。对于一组特定的输入参数,这给了我一个错误,上面写着“无法创建 Java 虚拟机”。我需要通过 PeekNamedPipe() 将其导入 Delphi 代码并将其显示在应用程序中。我怎样才能做到这一点? Delphi 代码如下所示:

  begin
  securityAttr.nlength := SizeOf(TSecurityAttributes);
  securityAttr.binherithandle := true;
  securityAttr.lpsecuritydescriptor := nil;

  if CreatePipe (readPipe, writePipe, @securityAttr, 0) then
  begin

  buffer  := AllocMem(READ_BUFFER + 1);
  FillChar(startInfo, Sizeof(startInfo), #0);
  startInfo.cb          := SizeOf(startInfo);
  startInfo.hStdOutput  := writePipe;
  startInfo.hStdInput   := readPipe;
  startInfo.dwFlags     := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
  startInfo.wShowWindow := SW_HIDE;

  if SearchPath(nil, PChar(consoleApp), '.exe', SizeOf(consoleAppBuf), consoleAppBuf, exeName) = 0 then
  raise EInOutError.CreateFmt('Could not find file %s', [consoleApp]);

FmtStr(commandLine, '"%s" %s', [consoleAppBuf, parameters]);

if CreateProcess(nil, PChar(commandLine), nil, nil, true, CREATE_NO_WINDOW, nil, nil, startInfo, processInfo) then
begin

  totalBytesRead := 0;

  repeat        
    exitCode := WaitForSingleObject(ProcessInfo.hProcess, 100);
    Application.ProcessMessages;

    if (PeekNamedPipe(readPipe, @buffer[totalBytesRead],
                         READ_BUFFER, @bytesRead,
                         @totalBytesAvail, @bytesLeftThisMessage)) then
    begin

      if (bytesRead > 0) then
        ReadFile(readPipe, buffer[totalBytesRead], bytesRead, bytesRead, nil);

      totalBytesRead := totalBytesRead + bytesRead;

    end;

  until (exitCode <> WAIT_TIMEOUT);

  GetExitCodeProcess(ProcessInfo.hProcess, result);

  buffer[totalBytesRead]:= #0;
  OemToChar(buffer, buffer);
  output.Text := output.Text + StrPas(buffer);

  FreeMem(buffer);
  CloseHandle(processInfo.hProcess);
  CloseHandle(processInfo.hThread);
  CloseHandle(readPipe);
  CloseHandle(writePipe);

end
else
  RaiseLastWin32Error;

end;

如何读取 java.exe 抛出的错误?

【问题讨论】:

  • 为什么把进程的标准输入/输出连接到同一个管道?你想通过这样做来达到什么目的?或者你只是随机尝试使用管道?这段代码有什么作用吗?流程的输出到哪里去了?标准输出还是标准错误?
  • 这是一个从delphi函数中运行的sn-p控制台应用程序。它将为命令行参数 createProcess() 并读取进程的结果。该过程的输出进入 PeekNamedPipe 的输入缓冲区。然而,这只发生在 java.exe 成功运行且没有任何错误时。我需要捕获运行 java.exe 时抛出的错误
  • 请再次发表评论。为什么将同一管道的两端连接到相同的工艺标准手柄?
  • 您正在将子进程的标准输出重定向到子进程的标准输入。次要:您不必轮询管道句柄,它会在数据可用时发出信号。
  • 不确定这是如何工作的。我假设创建了一个 ReadPipe 并且 PeekNamedPipe() 是从控制台应用程序输出读取输出。

标签: delphi console-application


【解决方案1】:

将同一管道的两端连接到同一进程的输入和输出是错误的。您正在将流程的输出反馈到其输入中。将hStdInput 保留为NULL

您还可以快速轻松地进行错误检查,并冒着泄漏句柄的风险,因为您不使用 finally 块。而且我不热衷于繁忙的循环。或致电ProcessMessages

撇开这些不谈,您不阅读错误的可能原因是它们进入了 stderr。将管道的写入端连接到 stderr 以及 stdout:

startInfo.hStdOutput  := writePipe;
startInfo.hStdError  := writePipe;

【讨论】:

  • 我阅读了更多关于在流程中使用 NamedPipe 的概念。意识到将管道的两端连接到进程的 i/p 和 o/p 是错误的。更正了。此外,将 hStdError 添加到我的 startInfo 并且它有效!谢谢
猜你喜欢
  • 2019-01-30
  • 2012-02-28
  • 1970-01-01
  • 2013-02-11
  • 2011-01-22
  • 1970-01-01
  • 2017-07-21
  • 2012-01-24
  • 1970-01-01
相关资源
最近更新 更多