1

From a C# form I am running a process with start info similar to Redirect console output to textbox in separate program and C# get process output while running, the process runs correctly however the output takes a long time to appear in the DataReceived event.

I would like to see the text as soon as the process generates it; according to Process standard output cannot be captured? (first comment) I need to wait until a buffer of 2 to 4 kb to fill before the event is fired.

As requested this is the code:

void pcs_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
    if (!string.IsNullOrEmpty(e.Data)) 
        textBox1.BeginInvoke((Action)delegate { textBox1.AppendText(text + "\n"); });
}

private void LER_Go_Click(object sender, EventArgs e)
{
    // variables LiDARExtRep contains the full path to an executable file
    // that runs in DOS and produces verbose output.
    // LER_Path.Text is the parameter passed to LiDARExtRep (only one arg for this example)
    ProcessStartInfo pStartInfo = new ProcessStartInfo(LiDARExtRep, LER_Path.Text);    
    pStartInfo.UseShellExecute = false;
    pStartInfo.ErrorDialog = false;
    pStartInfo.RedirectStandardError = true;
    pStartInfo.RedirectStandardInput = true;
    pStartInfo.RedirectStandardOutput = true;
    pStartInfo.CreateNoWindow = true;

    System.Diagnostics.Process pcs = new System.Diagnostics.Process();
    pcs.StartInfo = pStartInfo;

    bool pStarted = pcs.Start();

    pcs.OutputDataReceived += new DataReceivedEventHandler(pcs_OutputDataReceived);

    pcs.BeginOutputReadLine();
    pcs.WaitForExit();
}

I don't see anything special about it, it's exactly the same as the examples I referenced... a simple "Dir","/b/s" in the constructor should produce the same results.

Is there a way to diminish the buffer to a few bytes or a better way to execute a command line tool and receive the output 'real time'?

Background: I wrote a number of command line programs in C++, which work great, but the younger generation seem scared of DOS, so I am creating a form (GUI) to collect the parameters for these tools as it seems a lot less work than trying to put a GUI on each program in C++. If I can't get real time responses I will have to UseShellExecute = true; and show the command window.

Community
  • 1
  • 1
Michael Stimson
  • 314
  • 1
  • 4
  • 19
  • Perhaps you can run your process inside a BackGroundWorker https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker%28v=vs.110%29.aspx – jmc Jul 01 '15 at 05:28
  • How would that help @jmc? Is there a feedback on the BackgroundWorker that will take stdout from the executable? All I see there is a percentage. – Michael Stimson Jul 01 '15 at 05:30
  • Can you post your reproducible code for running the process? Then someone could find a clue. – emoacht Jul 01 '15 at 15:33
  • @emoacht, I have included the code. It is (almost) a direct copy of the help code at MSN/Stack Overflow (thank you to the respective authors). – Michael Stimson Jul 01 '15 at 21:21
  • AFAIK, buffering happens on console program end. It detect that output was redirected and enable buffed output. So, unless you can alter source of console program and make it flush its buffer after each line, nothing can be done. – user4003407 Jul 02 '15 at 01:19
  • @PetSerAl, they're my programs, so I can adjust the source code; though I'd prefer not to modify them much if I can help it. Nothing special is occurring in them with respect to I/O just printf statements. How would the buffer be set on the console program side? Normally the text occurs in the console window as soon as the printf is executed. – Michael Stimson Jul 02 '15 at 01:28
  • 1
    `setvbuf(stdout,NULL,_IONBF,0);` before first `printf` command should help. – user4003407 Jul 02 '15 at 01:43
  • @PetSerAl THAT'S IT! One small change in the C++ source for each program. Please put that in as an answer. – Michael Stimson Jul 02 '15 at 01:58

1 Answers1

5

The buffering happens on console program end. By default, stdout is fully buffered if known to be redirected:

If stdout is known to not refer to an interactive device, the stream is fully buffered. Otherwise, it is library-dependent whether the stream is line buffered or not buffered by default (see setvbuf). Source

So, unless you can alter the console program source to disable buffering, nothing can be done on GUI program side.

user4003407
  • 21,204
  • 4
  • 50
  • 60
  • Thank you so much, it's working like a charm now... every line is appearing in the listbox quickly. One thing though, I had to change the process.WaitForExit(); to do { application.DoEvents();} while (!process.HasExited); to get the form to respond properly. – Michael Stimson Jul 02 '15 at 02:17
  • 1
    @MichaelMiles-Stimson IMO, it is better do attach handler to `process.Exited` instead of `process.WaitForExit()` or `while (!process.HasExited)`. – user4003407 Jul 02 '15 at 02:35