■No34644に追記(魔界の仮面弁士の記事)
> ただし、標準出力された内容の末尾が改行で無いと> OutputDataReceived イベントが発生しない点にご注意ください。
Process.OutputDataReceived イベントの代わりに
StandardOutput.ReadAsync メソッドを使うようにしてみました。
これなら「PAUSE」や「TIME」にも対応できるかと思います。
Public Class Form1
Private proc As Process
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Me.components Is Nothing Then
Me.components = New System.ComponentModel.Container()
End If
Button1.Text = "開始"
Button2.Text = "標準入力を渡す"
Button2.Enabled = False
'コマンド
TextBox1.Text = Environment.GetEnvironmentVariable("ComSpec")
'引数
TextBox2.Text = ""
'標準入力の内容
TextBox3.Text = "DIR /D ""C:\Program Files (x86)\"""
'標準出力 & 標準エラー出力
RichTextBox1.ReadOnly = True
RichTextBox1.BackColor = Color.Black
RichTextBox1.ForeColor = Color.White
RichTextBox1.ScrollBars = RichTextBoxScrollBars.Both
RichTextBox1.WordWrap = False
RichTextBox1.HideSelection = False
End Sub
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
TextBox1.ReadOnly = True
TextBox2.ReadOnly = True
RichTextBox1.Clear()
Button2.Enabled = True
proc = Process.Start(New ProcessStartInfo(TextBox1.Text, TextBox2.Text) With
{
.UseShellExecute = False,
.CreateNoWindow = True,
.RedirectStandardInput = True,
.RedirectStandardOutput = True,
.RedirectStandardError = True
})
Me.components.Add(proc)
Await Task.WhenAll(
ConsumeOutput(proc.StandardOutput, False),
ConsumeOutput(proc.StandardError, True),
Task.Run(AddressOf proc.WaitForExit)
)
proc.Close()
Me.components.Remove(proc)
TextBox1.ReadOnly = False
TextBox2.ReadOnly = False
Button2.Enabled = False
Button1.Enabled = True
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If proc IsNot Nothing Then
proc.StandardInput.Write(TextBox3.Text & vbLf)
Else
Debug.WriteLine("既に閉じられている")
End If
End Sub
Private Async Function ConsumeOutput(reader As System.IO.TextReader, isError As Boolean) As Task
Dim buffer(2047) As Char
Dim length As Integer = Await reader.ReadAsync(buffer, 0, buffer.Length)
Dim foreColor = If(isError, Color.Yellow, Color.White)
Dim backColor = If(isError, Color.Red, Color.Empty)
While length > 0
Dim message As New String(buffer, 0, length)
Invoke(
New MethodInvoker(
Sub()
Dim pos = RichTextBox1.TextLength
RichTextBox1.Select(pos, 0)
RichTextBox1.SelectedText = If(message, "")
RichTextBox1.Select(pos, length)
RichTextBox1.SelectionColor = foreColor
RichTextBox1.SelectionBackColor = backColor
RichTextBox1.SelectionStart = RichTextBox1.TextLength
End Sub
)
)
length = Await reader.ReadAsync(buffer, 0, buffer.Length)
End While
End Function
End Class