vb.netvisual-studio-2010richtextboxappendtextconsole-redirect

Redirecting process output to a richtextbox


I'm attempting to redirect the output of a third party command line tool which is launched by my application. I am outputting to a rich text box. This is working successfully, with one exception.

When I test with a ping command, my output not formatted correctly. one line is appended to the previous. When I try to put a VbNewLine in there or a VbCrLf or a Environment.NewLine is puts an extra blank line.

I get this output:

Pinging 8.8.8.8 with 32 bytes of data:



Reply from 8.8.8.8: bytes=32 time=29ms TTL=44

Reply from 8.8.8.8: bytes=32 time=29ms TTL=44

Reply from 8.8.8.8: bytes=32 time=30ms TTL=44

Reply from 8.8.8.8: bytes=32 time=29ms TTL=44




Ping statistics for 8.8.8.8:

    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),

Approximate round trip times in milli-seconds:

    Minimum = 29ms, Maximum = 30ms, Average = 29ms

I want to get (as it is in a CMD window):

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=31ms TTL=44
Reply from 8.8.8.8: bytes=32 time=29ms TTL=44
Reply from 8.8.8.8: bytes=32 time=29ms TTL=44
Reply from 8.8.8.8: bytes=32 time=29ms TTL=44

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 29ms, Maximum = 31ms, Average = 29ms

I'm sure it's very simple, but can't figure it out.

Here's the code I'm using.

Private Sub StartProcess()

    Dim Proc = New Process()

    Proc.StartInfo.FileName = "ping"
    Proc.StartInfo.Arguments = "8.8.8.8"

    Proc.StartInfo.RedirectStandardOutput = True
    Proc.StartInfo.RedirectStandardError = True
    Proc.EnableRaisingEvents = True
    Application.DoEvents()
    Proc.StartInfo.CreateNoWindow = True
    Proc.StartInfo.UseShellExecute = False

    AddHandler Proc.ErrorDataReceived, AddressOf proc_OutputDataReceived
    AddHandler Proc.OutputDataReceived, AddressOf proc_OutputDataReceived
    Proc.Start()
    Proc.BeginErrorReadLine()
    Proc.BeginOutputReadLine()
    'Proc.WaitForExit()

End Sub


Delegate Sub UpdateTextBoxDelg(ByVal text As String)
Public myDelegate As UpdateTextBoxDelg = New UpdateTextBoxDelg(AddressOf UpdateTextBox)

Public Sub UpdateTextBox(ByVal text As String)
    box_output.AppendText(text)
End Sub

Public Sub proc_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
    On Error Resume Next
    If Me.InvokeRequired = True Then
        Me.Invoke(myDelegate, e.Data)
    Else
        UpdateTextBox(e.Data)
    End If

End Sub

Solution

  • Bit of a stumper, took me a while. I noticed that e.Data can be Nothing, never seen that before. The network utilities are, erm, special, Berkeley is an unusual place on planet Earth.

    You do have to add the line-ending yourself. Using InvokeRequired is pointless, it always is for the OutputDataReceived event. This version worked fine:

    Public Sub proc_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
        If e.Data IsNot Nothing Then Me.Invoke(myDelegate, e.Data + vbCrLf)
    End Sub
    

    Please use the System.Net.NetworkInformation.Ping class instead. It is not quite as affected by recreational chemical substances.