I am writing a C# application that can launch third party command line executables and redirect their standard output to a RichTextBox.
I am able to redirect the output alright by using the process.OutputDataReceived event. I have a queue that I push lines to, and then I use a timer to periodically dump all the queued lines into the RichTextBox.
This works perfectly for some third party programs.
The problem lies with programs that write to a single line of the console multiple times. eg: 5% -> 10% -> 25% etc... (constantly rewriting the same spot) This is done, I suppose, by not putting a line feed character, but rather simply returning to the beginning of the line with a carriage return and writing over the previous characters.
What happens is that the OutputDataReceived does not seem to have any way of indicating if a new line should be applied or not so my RichTextBox output simply has multiple updates on new lines. eg: 5% 10% 25% etc...
Is there any way to tell if the standard output is going on a new line or the same line?
This code will fix up raw output and make it as it would appear on the terminal.
If I understand correctly, you are currently seeing progress updates reported to your
RichTextBox
control as individual lines, while you would like to emulate the behavior of the console window. I.e. to overwrite the previously output line with the new one, rather than keeping the previous line and adding a new one. With that in mind…The .NET types, including things like
TextReader
and theProcess
class's handling of output, consider a newline to be any of\r
,\n
, or\r\n
. So even a process that is simply using a\r
to overwrite the current line would still be interpreted byOutputDataReceived
as starting a new line. Given how consistent this behavior is across .NET, your only real option is to avoid using any built-in line-based I/O mechanisms.Fortunately, you can get asynchronous reads from the process directly via
StandardOutput
, instead of having to handle the line-basedOutputDataReceived
event. For example:You might call it like this:
Of course, without any modification the above will just do what you are already getting. But reading the output this way will not do any interpretation of the line-break characters. Instead, they will be present in the string
s
that is passed to the anonymous method handling each read callback. So you can scan that string yourself, looking for lone carriage returns that indicate that you are starting a new line, but should delete the previous line before adding the new text. Be sure to add (or at least skip) all of the text up to the carriage return first, and then delete the last line, before adding the new text.