Visual Basic捕获cmd的输出

我希望Visual Basic能够在目录“C:\ projectTest \”上运行“make”命令。

我试图用这个:

Dim output As String = String.Empty Using Process As New Process Process.StartInfo = New ProcessStartInfo("cmd") Process.StartInfo.WorkingDirectory = "C:\projectTest\" Process.StartInfo.UseShellExecute = False Process.StartInfo.CreateNoWindow = True Process.StartInfo.RedirectStandardInput = True Process.StartInfo.RedirectStandardOutput = True Process.StartInfo.RedirectStandardError = True Process.Start() Process.BeginOutputReadLine() AddHandler Process.OutputDataReceived, _ Sub(processSender As Object, lineOut As DataReceivedEventArgs) output += lineOut.Data + vbCrLf End Sub Using InputStream As System.IO.StreamWriter = Process.StandardInput InputStream.AutoFlush = False InputStream.WriteLine("make") End Using Do Application.DoEvents() Loop Until Process.HasExited End Using 

这段代码能够捕获控制台的“gcc …”部分(来自Makefile),但不会捕获错误(如果手动打开cmd并在该目录上运行make,会popup错误消息)。

如何捕获包括错误在内的所有信息?

不止一个问题。 首先,由于@ shf301已经告诉你,你忘了阅读stderr。 他又忘了添加一行:

  Process.Start() AddHandler Process.OutputDataReceived, _ Sub(processSender As Object, lineOut As DataReceivedEventArgs) output += lineOut.Data + vbCrLf End Sub Process.BeginOutputReadLine() AddHandler Process.ErrorDataReceived, _ Sub(processSender As Object, lineOut As DataReceivedEventArgs) output += lineOut.Data + vbCrLf End Sub Process.BeginErrorReadLine() 

还有一个非常麻烦的问题,你的事件处理程序运行迟。 他们这个过程已经退出之后开火。 这些处理程序在线程池线程上运行的副作用。 在使用输出变量之前,您需要等待一个任意的(不可估量的)时间量:

  Do Application.DoEvents() Loop Until Process.HasExited System.Threading.Thread.Sleep(1000) 

这太难看了 这样做, 任何 IDE或编辑器的方式。 将输出重定向到一个临时文件,然后读取文件:

  Dim tempfile As String = System.IO.Path.GetTempFileName Using Process As New Process Process.StartInfo = New ProcessStartInfo("cmd.exe") Process.StartInfo.Arguments = "/c make 1> """ + tempfile + """ 2>&1" Process.StartInfo.WorkingDirectory = "C:\projectTest" Process.StartInfo.UseShellExecute = False Process.StartInfo.CreateNoWindow = True Process.Start() Process.WaitForExit() output = System.IO.File.ReadAllText(tempfile) System.IO.File.Delete(tempfile) End Using 

神秘的命令行的一些注释:

  • / c告诉cmd.exe只执行一个命令,然后退出
  • 1>将输出重定向到临时文件
  • 2>&1告诉cmd.exe将stderr重定向到stdout
  • 三重双引号确保临时文件名中的空格不会造成麻烦。

同样的2>&1也会解决你原来的问题;)

错误通常写入StandardError流,您只能读取StandardOutput流。 ErrorDataReceived事件添加事件处理程序,您应该看到错误。

 AddHandler Process.ErrorDataReceived, _ Sub(processSender As Object, lineOut As DataReceivedEventArgs) output += lineOut.Data + vbCrLf End Sub 

像我这样的人,想知道为什么我们不能得到错误的流,在异步模式。 添加行

 process.BeginErrorReadLine()