简体   繁体   English

Visual Basic捕获cmd的输出

[英]Visual Basic Capture output of cmd

I want Visual Basic to be able to run the "make" command on the directory "C:\\projectTest\\". 我希望Visual Basic能够在目录“C:\\ projectTest \\”上运行“make”命令。

I tried to use this: 我试着用这个:

    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

This code is able to capture the "gcc ..." part of the console (comes from the Makefile), but will not capture the error (which does pop up if I manually open cmd and run make on that directory). 此代码能够捕获控制台的“gcc ...”部分(来自Makefile),但不会捕获错误(如果我手动打开cmd并在该目录上运行make,则会弹出错误)。

How can I capture everything that appears including the error? 如何捕获出现的所有内容,包括错误?

More than one problem. 不止一个问题。 First off, as @shf301 already told you, you forgot to read stderr. 首先,正如@ shf301已经告诉过你的那样,你忘了阅读stderr。 He in turn forgot to add an extra line: 他反过来忘了添加额外的一行:

    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()

There's another very cumbersome problem, your event handlers run late. 还有一个非常麻烦的问题,你的事件处理程序运行得很晚。 They fire after the process has already exited. 他们这个过程已经退出之后开火。 A side effect of these handlers running on a thread-pool thread. 这些处理程序在线程池线程上运行的副作用。 You'll need to wait for an arbitrary (and unguessable) amount of time before you use the output variable: 在使用输出变量之前,您需要等待任意(且不可饶恕)的时间量:

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

This is too ugly. 这太难看了。 Do this the way that any IDE or editor does it. 按照任何 IDE或编辑器的方式执行此操作。 Redirect the output to a temporary file and read the file afterwards: 将输出重定向到临时文件,然后读取文件:

    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

Some annotation with the mystic command line: 使用mystic命令行进行一些注释:

  • /c tells cmd.exe to execute just the single command and then exit / c告诉cmd.exe只执行单个命令然后退出
  • 1> redirects the output to the temporary file 1>将输出重定向到临时文件
  • 2>&1 tells cmd.exe to redirect stderr to stdout 2>&1告诉cmd.exe将stderr重定向到stdout
  • the triple double quotes ensures that spaces in the tempfile name don't cause trouble. 三重双引号确保临时文件名中的空格不会造成麻烦。

That same 2>&1 would also have fixed your original problem ;) 那个2>&1也会解决你原来的问题;)

Errors are generally written to the StandardError stream and you are only reading the StandardOutput stream. 错误通常写入StandardError流,您只读取StandardOutput流。 Add an event handler for the ErrorDataReceived event and you should see the errors. ErrorDataReceived事件添加事件处理程序,您应该看到错误。

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

for people like me that are wondering why we cant get errorstream, in async mode. 像我这样的人想知道为什么我们不能在异步模式下得到错误。 add line 添加行

process.BeginErrorReadLine()

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

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