I have written a custom console application which redirects output to/from the command I am running (in the screenshot I am running 'cmd.exe') to a richtextbox control. The font being used is 'Lucida Console' which is the same font being used by 'cmd.exe' itself.
The problem I face, is that certain characters are not being displayed properly, however they are the correct character for that command. At best guess, these are ANSI terminal characters which must be escaped / processed / whatever, but I am unsure. So this doesn't become an XY problem, I will be clear with my intentions:
I would like to display these characters in the richtextbox the same as they are displayed when running 'cmd.exe'. The language I am using is C# on .NET Framework 4.5 with no extra controls. I am redirecting the output/input from System.Diagnostics.Process.Start() and the RichTextBox control.
Relevant Code :
void processInterace_OnProcessOutput( object sender, ProcessEventArgs args ) {
// Write the output
string outp = Encoding.GetEncoding(437).GetString(Encoding.GetEncoding(437).GetBytes(args.Content.Substring(lastInput.Length).ToCharArray()));
WriteOutput( outp, ForeColor );
lastInput="";
// Fire the output event.
FireConsoleOutputEvent( args.Content );
}
public void WriteOutput( string output, Color color ) {
if ( string.IsNullOrEmpty( lastInput )==false&&
( output==lastInput||output.Replace( "\r\n", "" )==lastInput ) )
return;
if ( !this.IsHandleCreated )
return;
Invoke( (Action)( () => {
// Write the output.
richTextBoxConsole.Focus();
richTextBoxConsole.SelectionColor=color;
richTextBoxConsole.SelectedText+=output;
inputStart=richTextBoxConsole.SelectionStart;
} ) );
}
public void StartProcess( string fileName, string arguments ) {
// Are we showing diagnostics?
if ( ShowDiagnostics ) {
WriteOutput( "Preparing to run "+fileName, DiagnosticsColor );
if ( !string.IsNullOrEmpty( arguments ) )
WriteOutput( " with arguments "+arguments+"."+Environment.NewLine, DiagnosticsColor );
else
WriteOutput( "."+Environment.NewLine, DiagnosticsColor );
}
// Start the process.
processInterace.StartProcess( fileName, arguments );
// If we enable input, make the control not read only.
if ( IsInputEnabled )
richTextBoxConsole.ReadOnly=false;
}
And the hook (that matters)
processInterace.OnProcessOutput+=processInterace_OnProcessOutput;
UPDATE
So I decided to try a new approach to resolve this problem. Since ProcessInterface
doesn't appear to give any real control over changing the encoding of the output recieved from the process, I decided to try using the raw Process
interface as follows :
public partial class Form1 : Form {
Process process { get; set; }
ProcessStartInfo startinfo { get; set; }
public Form1() {
InitializeComponent();
process = new Process();
startinfo = new ProcessStartInfo() {
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
StandardErrorEncoding = System.Text.Encoding.GetEncoding(437),
StandardOutputEncoding = System.Text.Encoding.GetEncoding(437),
UseShellExecute = false,
ErrorDialog = false,
CreateNoWindow = true,
WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
//WindowStyle=System.Diagnostics.ProcessWindowStyle.Normal
};
}
void process_ErrorDataReceived( object sender, DataReceivedEventArgs e ) {
Invoke( (Action)( () => {
cb.Text+=e.Data+"\n";
} ) );
}
void process_Exited( object sender, EventArgs e ) {
this.Text = "Exited";
}
private void Form1_Load( object sender, EventArgs e ) {
process.StartInfo.Arguments = "/K tree";
startinfo.FileName="cmd.exe";
process=new Process {
StartInfo = startinfo
};
process.OutputDataReceived+=process_OutputDataReceived;
process.ErrorDataReceived+=process_ErrorDataReceived;
process.Exited+=process_Exited;
process.EnableRaisingEvents=true;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
}
void process_OutputDataReceived( object sender, DataReceivedEventArgs e ) {
Invoke( (Action)( () => {
cb.Text+=e.Data + "\n";
} ) );
}
}
This results in a new problem. I am not getting an event notification on all new data -- only on new lines terminated in a carriage return. An example of the output is depicted in the image below :
When I alter form_Load
in my recent example, you can see that this finally fixes the encoding issue, but a new problem exists where the last line is not being returned until a carriage return is sent from the console:
private async void Form1_Load( object sender, EventArgs e ) {
process.StartInfo.Arguments = "";
startinfo.FileName="cmd.exe";
process=new Process {
StartInfo = startinfo
};
process.OutputDataReceived+=process_OutputDataReceived;
process.ErrorDataReceived+=process_ErrorDataReceived;
process.Exited+=process_Exited;
process.EnableRaisingEvents=true;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
await process.StandardInput.WriteLineAsync( @"tree d:\sqlite" );
}