DOBON.NETプログラミング道掲示板

■34642 / 親記事)  VB.net非同期処理でtextboxに出力したい
  
□投稿者/ ゆき 一般人(1回)-(2021/02/12(Fri) 08:45:02)
  • アイコン環境/言語:[win10 VB.net 最新版] 
    分類:[.NET] 

    https://dobon.net/vb/dotnet/process/standardoutput.html

    この中の「コマンドプロンプトに文字列を入力することで、複数のコマンドを実行する」の項目はコンソールに出力していますがこれをテキストボックスに出力ししたいと考えています。
    調べたところデリゲート処理が必要らしいのですがどのように改定いうかわかりません。
    教えて下さい。

マルチポストを報告
違反を報告
引用返信 削除キー/
■34644 / ResNo.1)  Re[1]: VB.net非同期処理でtextboxに出力したい
□投稿者/ 魔界の仮面弁士 大御所(1314回)-(2021/02/12(Fri) 11:00:27)
  • アイコン
    No34642に返信(ゆきさんの記事)
    > 調べたところデリゲート処理が必要らしいのですがどのように改定いうかわかりません。
    
    たとえばこんな感じ。
    
    Public Class Form1
        Private WithEvents 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)
            proc.BeginOutputReadLine()
            proc.BeginErrorReadLine()
            Await 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 Sub proc_OutputDataReceived(sender As Object, e As DataReceivedEventArgs) Handles proc.OutputDataReceived
            StandardOut(e.Data, isError:=False)
        End Sub
        Private Sub proc_ErrorDataReceived(sender As Object, e As DataReceivedEventArgs) Handles proc.ErrorDataReceived
            StandardOut(e.Data, isError:=True)
        End Sub
        Private Sub StandardOut(message As String, isError As Boolean)
            Invoke(
                New MethodInvoker(
                   Sub()
                       Dim s = RichTextBox1.TextLength
                       Dim l = If(message?.Length, 0)
                       RichTextBox1.SelectionStart = s
                       RichTextBox1.SelectedText = If(message, "")
                       RichTextBox1.Select(s, l)
                       RichTextBox1.SelectionColor = If(isError, Color.Yellow, RichTextBox1.ForeColor)
                       RichTextBox1.SelectionBackColor = If(isError, Color.Red, RichTextBox1.BackColor)
                       RichTextBox1.SelectionStart = RichTextBox1.TextLength
                       RichTextBox1.SelectedText = vbCr
                   End Sub
                )
            )
        End Sub
    End Class
    
    
    ただし、標準出力された内容の末尾が改行で無いと
    OutputDataReceived イベントが発生しない点にご注意ください。
    
    「TIME /T」の結果は改行が来るのですぐに表示されますが、
    「TIME」は改行を伴わないため、次の応答が来るまでイベントが発生しません。
    
    「PAUSE」コマンドなどとも相性が悪いですね。

違反を報告
引用返信 削除キー/
■34645 / ResNo.2)  Re[2]: VB.net非同期処理でtextboxに出力したい
□投稿者/ 魔界の仮面弁士 大御所(1315回)-(2021/02/12(Fri) 11:47:14)
  • アイコン
    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

違反を報告
引用返信 削除キー/



スレッド内ページ移動 / << 0 >>

このスレッドに書きこむ

Mode/  Pass/


- Child Tree -