cmd 的 Visual Basic 捕获输出 [英] Visual Basic Capture output of cmd
问题描述
我希望 Visual Basic 能够在目录C:projectTest"上运行make"命令.
I want Visual Basic to be able to run the "make" command on the directory "C:projectTest".
我尝试使用这个:
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 会弹出).
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).
如何捕获出现的所有内容,包括错误?
How can I capture everything that appears including the error?
推荐答案
不止一个问题.首先,正如@shf301 已经告诉您的那样,您忘记阅读 stderr.他反过来忘记添加额外的一行:
More than one problem. First off, as @shf301 already told you, you forgot to read 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()
还有另一个非常麻烦的问题,您的事件处理程序运行晚了.他们在进程已经退出之后触发.这些处理程序在线程池线程上运行的副作用.在使用 output 变量之前,您需要等待一段任意(且不可猜测)的时间:
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)
这太丑了.以任何 IDE 或编辑器的方式执行此操作.将输出重定向到一个临时文件,然后读取该文件:
This is too ugly. Do this the way that any IDE or editor does it. 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:
- /c 告诉 cmd.exe 只执行单个命令然后退出
- 1> 将输出重定向到临时文件
- 2>&1 告诉 cmd.exe 将 stderr 重定向到 stdout
- 三重双引号确保临时文件名称中的空格不会造成麻烦.
同样的 2>&1
也可以解决你原来的问题;)
That same 2>&1
would also have fixed your original problem ;)
这篇关于cmd 的 Visual Basic 捕获输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!