6

what is wrong why is that the richtextbox doesnt get the stream of Process output? theres no text display in richtextbox..

 private void button1_Click(object sender, EventArgs e)
    {

        Process sortProcess;
        sortProcess = new Process();
        sortProcess.StartInfo.FileName = "sort.exe";
        sortProcess.StartInfo.Arguments = this.comboBox1.SelectedItem.ToString();
        // Set UseShellExecute to false for redirection.
        sortProcess.StartInfo.CreateNoWindow = true;
        sortProcess.StartInfo.UseShellExecute = false;



        // Redirect the standard output of the sort command.  
        // This stream is read asynchronously using an event handler.
        sortProcess.StartInfo.RedirectStandardOutput = true;
        sortOutput = new StringBuilder("");

        // Set our event handler to asynchronously read the sort output.
        sortProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);

        // Redirect standard input as well.  This stream
        // is used synchronously.
        sortProcess.StartInfo.RedirectStandardInput = true;

        // Start the process.
        sortProcess.Start();



        // Start the asynchronous read of the sort output stream.
        sortProcess.BeginOutputReadLine();
        sortProcess.WaitForExit();


        richTextBox1.AppendText(sortOutput.ToString());
    }

    private static void SortOutputHandler(object sendingProcess,
        DataReceivedEventArgs outLine)
    {
            sortOutput.Append(Environment.NewLine +
                "[" + numOutputLines.ToString() + "] - " + outLine.Data);
        }
    }

so when sort.exe launches, it displays text, i want all those text be displayed also in richtextbox in RealTime (i dont want to wait for the process to exit, and then read all output)

how can i do it? any wrong part of my code? thanks

UPDATE @botz

i added this in my code

 private void SortOutputHandler(object sendingProcess,
        DataReceivedEventArgs outLine)
    {

            sortOutput.Append(Environment.NewLine +
                "[" + numOutputLines.ToString() + "] - " + outLine.Data);
            richTextBox1.AppendText(sortOutput.ToString());


    }

but it throws this exception

Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.
J. Steen
  • 15,470
  • 15
  • 56
  • 63
Lufthansa
  • 145
  • 1
  • 2
  • 12
  • By definition of what a sort does, it is impossible for there to be any output until all the input has been read. So the sort program is a bad example of getting output in realtime. – Sam Hobbs Jan 16 '19 at 18:57
  • Did your issue solve? I too not able to get anything in Console / RichTextBox. What was the approach you followed? – harsha.cs Sep 22 '21 at 09:19

5 Answers5

7

WaitForExit() blocks your UI Thread, so you don't see the new output. Either wait for the process in a separate thread or replace WaitForExit() with something like this:

while (!sortProcess.HasExited) {
     Application.DoEvents(); // This keeps your form responsive by processing events
}

In your SortOutputHandler, you can now directly append output to your textbox. But you should remember to check if you need to invoke it on the UI Thread.

You can check if it's on the UI thread this way in your handler:

    if (richTextBox1.InvokeRequired) { richTextBox1.BeginInvoke(new DataReceivedEventHandler(SortOutputHandler), new[] { sendingProcess, outLine }); }
    else {
        sortOutput.Append(Environment.NewLine + "[" + numOutputLines.ToString() + "] - " + outLine.Data);
        richTextBox1.AppendText(sortOutput.ToString());
    }
Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • thanks botz,, what is this [ Application.DoEvents(); // This lets your ] – Lufthansa Jun 29 '11 at 13:47
  • 1
    oops. edited my post. basically it processes clicks, pending repaints (such as your textbox if text was appended) and other events. – Botz3000 Jun 29 '11 at 13:55
  • i tried your code,, but i get exception, check my edited post thanks – Lufthansa Jun 29 '11 at 13:59
  • tried the new event handler, but still doesnt get text displayed in richtextbox. what could be the problem? all redirections are fine.. – Lufthansa Jun 29 '11 at 14:14
  • Line 171 in Form1.cs - change sortProcess.WaitForExit() to the first block of code in my post (forgot to include the while when first posting) – Botz3000 Jun 30 '11 at 06:52
  • @botz, thanks, can u upload the working code, that displays realtime text in richtextbox? Thanks very much – Lufthansa Jun 30 '11 at 09:36
  • no need to. Just tested it, you really just need to replace the sortProcess.WaitForExit() with the first block of code in my post. – Botz3000 Jun 30 '11 at 10:18
  • Tnx. Ill try it when im home. For the mean time, did the edited portion made the rictxtbox display realtime output? Tnx so much – Lufthansa Jun 30 '11 at 12:11
  • @botz, i tried the new event handler --> http://pastebin.com/WMMdYuEs but the richtextbox is not updating.. the gui succesfully connects to the server but theres no realtime output generated. – Lufthansa Jun 30 '11 at 13:42
  • 1
    The handler is not the problem. The problem is the WaitForExit() call. Replace it: http://pastebin.com/KBazyE2D – Botz3000 Jun 30 '11 at 14:12
  • already replaced but no text is displayed in richtextbox --> http://pastebin.com/1bwpB05m – Lufthansa Jun 30 '11 at 14:28
  • PS: this what the output should look like PS: http://i51.tinypic.com/2wc2s9k.png those text should be shown in richtextbox in realtime.. thanks – Lufthansa Jun 30 '11 at 14:55
  • 1
    it works. It just looks like openvpn doesn't write to the standard output stream. try calling it without Arguments and you'll see. – Botz3000 Jun 30 '11 at 16:03
  • @botz,, theres a problem in the event handler, it gives this error: System.NullReferenceException was unhandled by user code – Lufthansa Jul 01 '11 at 00:43
  • would u mind helping me here -> http://stackoverflow.com/questions/6548543/start-a-process-executable-in-resources – Lufthansa Jul 01 '11 at 13:25
  • @Lufthansa if you search for Application.DoEvents() then you will find many comments from experienced Windows programmers saying it is unnecessary, except most of the comments are stronger than that. DoEvents was created for unmanaged VB but VB.Net and C# do not need it. – Sam Hobbs Jan 10 '19 at 01:30
5

This is working for me:

private void button1_Click(object sender, EventArgs e)
    {
        using (Process sortProcess = new Process())
        {
            sortProcess.StartInfo.FileName = @"F:\echo_hello.bat";
            sortProcess.StartInfo.CreateNoWindow = true;
            sortProcess.StartInfo.UseShellExecute = false;
            sortProcess.StartInfo.RedirectStandardOutput = true;

            // Set event handler
            sortProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);

            // Start the process.
            sortProcess.Start();

            // Start the asynchronous read
            sortProcess.BeginOutputReadLine();

            sortProcess.WaitForExit();
        }
    }

    void SortOutputHandler(object sender, DataReceivedEventArgs e)
    {
        Trace.WriteLine(e.Data);
        this.BeginInvoke(new MethodInvoker(() =>
        {
            richTextBox1.AppendText(e.Data ?? string.Empty);
        }));
    }

The example you started with was a console application, which doesn't care much about multithreaded access. For Windows Forms when you update a control this has to be done from the main UI thread, which is why BeginInvoke is needed. If you want to check rapidly if a handler like SortOutputHandler is working properly you can use System.Diagnostics.Trace.Write*, which doesn't need BeginInvoke.

EDIT: echo_hello.bat simply echoes the "hello" string:

@echo off
echo hello
Sorin Comanescu
  • 4,829
  • 3
  • 29
  • 38
  • @sorin,, ive pasted that code in my program.. mind if u take a look -> http://www.mediafire.com/?v1cpelnvzb7x558 when the process starts, my gui starts to hang,, and no running display is running in richtextbox. thanks – Lufthansa Jun 29 '11 at 23:04
  • @Lufthansa, that's because the process really doesn't exit (maybe will timeout at some point) for some options in the combobox (I tried with the first one). However, if you use the eighth option in the combobox it works as expected. – Sorin Comanescu Jun 30 '11 at 07:43
  • @Lufthansa, given the nature of the process you're calling I think a good measure would be to use `WaitForExit()` with the timeout option and log the timeout event in the RichTextBox in case it happens. – Sorin Comanescu Jun 30 '11 at 07:46
  • @Lufthansa, there's no change in the code: as I said before, the process called simply doesn't exit for some servers (maybe they're not reachable) and for this case you should call `WaitForExit(timeout)` where `timeout` is given in milliseconds. – Sorin Comanescu Jun 30 '11 at 10:38
  • @sorin, tnx but the server connection is not yet finished (it doesnt matter as of now). Im trying to get the openvpn.exe output displayed in rich textbox. Any idea? Tnx.... – Lufthansa Jun 30 '11 at 12:16
  • PS: this what the output should look like http://i51.tinypic.com/2wc2s9k.png those text should be shown in richtextbox in realtime.. thanks – Lufthansa Jun 30 '11 at 14:55
0

Complete application and source code available from this external link of codeproject :

http://www.codeproject.com/Articles/335909/Embedding-a-Console-in-a-C-Application

This is tutorial of implementation of https://github.com/dwmkerr/consolecontrol.

Harshal Doshi Jain
  • 2,567
  • 1
  • 20
  • 16
0

As I said in the comment I posted to the question, by definition of what a sort does, it is impossible for there to be any output until all the input has been read. So the sort program is a bad example of getting output in realtime. So the following is for anyone in the future that wants to do something like this for console programs in general. The following uses a BackgroundWorker to get the output asynchronously and put it into a TextBox. A RichTextBox could easily be used instead.

public partial class MainWindow : Window
{
    const string Path = @"C:\Windows\system32\sort.exe";
    BackgroundWorker Processer = new BackgroundWorker();

    public MainWindow()
    {
        InitializeComponent();
        Processer.WorkerReportsProgress = true;
        Processer.WorkerSupportsCancellation = true;
        Processer.ProgressChanged += Processer_ProgressChanged;
        Processer.DoWork += Processer_DoWork;
    }

    private void Processer_DoWork(object sender, DoWorkEventArgs e)
    {
        StreamReader StandardOutput = e.Argument as StreamReader;
        string data = StandardOutput.ReadLine();
        while (data != null)
        {
            Processer.ReportProgress(0, data);
            data = StandardOutput.ReadLine();
        }
    }

    private void Processer_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        string data = e.UserState as string;
        if (data != null)
            DataBox.Text += data + "\r\n";
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        DataBox.Text = string.Empty;
        ProcessStartInfo StartInfo = new ProcessStartInfo(Path);
        StartInfo.RedirectStandardOutput = true;
        StartInfo.RedirectStandardInput = true;
        StartInfo.UseShellExecute = false;
        Process p = null;
        try { p = Process.Start(StartInfo); }
        catch (Exception ex)
        {
            MessageBox.Show($"Error starting {Path}: {ex.Message}");
            return;
        }
        // Get the output
        Processer.RunWorkerAsync(p.StandardOutput);
        // Put the input
        p.StandardInput.WriteLine("John");
        p.StandardInput.WriteLine("Alice");
        p.StandardInput.WriteLine("Zoe");
        p.StandardInput.WriteLine("Bob");
        p.StandardInput.WriteLine("Mary");
        // Tell the program that is the last of the data
        p.StandardInput.Close();
    }
}

For the sort program it is not necessary to call ReportProgress until after all the data has been read but this is a more generalized sample.

Sam Hobbs
  • 2,594
  • 3
  • 21
  • 32
0

If you are going to update the ui from another thread, you need to make sure you are on the main ui thread. In the method check for InvokeRequired. See InvokeRequired

Rob
  • 3,026
  • 4
  • 30
  • 32
  • , i dont need the input as the program only displays, and it doesnt accept any input from the user.. how can i transfer the output to richtexbox in real time? thanks – Lufthansa Jun 29 '11 at 14:02
  • Yeah, I think i see what you are asking now. – Rob Jun 29 '11 at 14:07
  • thank you rob, i read that msdn documentation but i dont get how can i use InvokeRequired and where to use it? – Lufthansa Jun 29 '11 at 14:08
  • Take a look at this article http://blogs.msdn.com/b/csharpfaq/archive/2004/03/17/91685.aspx – Rob Jun 29 '11 at 14:11
  • , i already have the invoke method,, but nothing is displayed :( http://www.mediafire.com/?v1cpelnvzb7x558 – Lufthansa Jun 29 '11 at 23:05