Visual Basic捕获cmd的输出

时间:2013-12-20 16:08:52

标签: .net windows visual-studio vba process

我希望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,则会弹出错误)

如何捕获显示的所有内容,包括错误?

3 个答案:

答案 0 :(得分:7)

不止一个问题。首先,正如@ 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

使用mystic命令行进行一些注释:

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

同样的2>&1也会修复原来的问题;)

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

对于像我这样的人,我们想知道为什么我们无法在异步模式下获得错误。 添加行

process.BeginErrorReadLine()