C# - Output command prompt in real time to a text box [duplicate] - c#

I'm developing an Windows Forms application that requires me to call a separate program to perform a task. The program is a console application and I need to redirect standard output from the console to a TextBox in my program.
I have no problem executing the program from my application, but I don't know how to redirect the output to my application. I need to capture output while the program is running using events.
The console program isn't meant to stop running until my application stops and the text changes constantly at random intervals. What I'm attempting to do is simply hook output from the console to trigger an event handler which can then be used to update the TextBox.
I am using C# to code the program and using the .NET framework for development. The original application is not a .NET program.
EDIT:
Here's example code of what I'm trying to do. In my final app, I'll replace Console.WriteLine with code to update the TextBox. I tried to set a breakpoint in my event handler, and it isn't even reached.
void Method()
{
var p = new Process();
var path = #"C:\ConsoleApp.exe";
p.StartInfo.FileName = path;
p.StartInfo.UseShellExecute = false;
p.OutputDataReceived += p_OutputDataReceived;
p.Start();
}
static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(">>> {0}", e.Data);
}

This works for me:
void RunWithRedirect(string cmdPath)
{
var proc = new Process();
proc.StartInfo.FileName = cmdPath;
// set up output redirection
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.EnableRaisingEvents = true;
proc.StartInfo.CreateNoWindow = true;
// see below for output handler
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
// output will be in string e.Data
}

You can use the following code
MemoryStream mem = new MemoryStream(1000);
StreamWriter writer = new StreamWriter(mem);
Console.SetOut(writer);
Assembly assembly = Assembly.LoadFrom(#"C:\ConsoleApp.exe");
assembly.EntryPoint.Invoke(null, null);
writer.Close();
string s = Encoding.Default.GetString(mem.ToArray());
mem.Close();

I've added a number of helper methods to the O2 Platform (Open Source project) which allow you easily script an interaction with another process via the console output and input (see http://code.google.com/p/o2platform/source/browse/trunk/O2_Scripts/APIs/Windows/CmdExe/CmdExeAPI.cs)
Also useful for you might be the API that allows the viewing of the console output of the current process (in an existing control or popup window). See this blog post for more details: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (this blog also contains details of how to consume the console output of new processes)

Thanks to Marc Maxham for his answer that save me time !
As Jon of All Trades notice it, UseShellExecute must be set to false in order to redirect IO streams, otherwise the Start() call throws an InvalidOperationException.
Here is my modification of the code where txtOut is a WPF readonly Textbox
void RunWithRedirect(string cmdargs)
{
var proc = new Process()
{
StartInfo = new ProcessStartInfo("cmd.exe", "/k " + cmdargs)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
},
EnableRaisingEvents = true
};
// see below for output handler
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
Dispatcher.BeginInvoke(new Action( () => txtOut.Text += (Environment.NewLine + e.Data) ));
}

Related

Redirecting Continuous Output from a console to RichtextBox in C# Windows Form

I used this code to log the output from the exe in command prompt to RIchTextBox.
ProcessStartInfo psi = new ProcessStartInfo("adb.exe", "devices");
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
var proc = Process.Start(psi);
string s = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
richTextBox1.Text = s;
This is basically android command to get the list of connected devices. This works fines as it has just two lines.
If the output of the exe is continous data how it can be logged efficiently.
I replaced the command with adb.exe logcat but it hangs and nothing comes on the RichTextBox.
How can I log this coninous output on the RichetxtBox?
It's because you call ReadToEnd on the output stream; C# will keep reading it and reading it and only finish reading it when the stream closes. At that point your code carries on. Your task is more complex than you realize. To read incrementally you need something like:
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = Properties.Settings.Default.CommandLineFfmpegPath,
Arguments = string.Format(
Properties.Settings.Default.CommandLineFfmpegArgs,
OutputPath
),
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
};
var proc = System.Diagnostics.Process.Start(psi);
proc.OutputDataReceived += proc_OutputDataReceived;
proc.ErrorDataReceived += proc_ErrorDataReceived;
proc.BeginOutputReadLine();
And you need an event handler that will be called every time there is some data (but it will need to make sure it doesn't cause a cross thread violation), something like:
void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (richTextbox1.InvokeRequired)
richTextbox1.Invoke((MethodInvoker) delegate {this.Text += e.Data;});
else
richTextbox1.Text += e.Data;
}
I'm not sure I'd use something as heavy as a richtextbox for this.. You probably aren't formatting (unless the console output is colored and youre gonna reinterpret the color codes) so a textbox would do fine.
Oh, and you probably don't want to jam your UI thread by WaitForExit either

Process.Start a console application, input in it then get output in a Form

I would like to open a simple console application that looks like this :
static void Main(string[] args)
{
Console.WriteLine("Beginning");
string smth = Console.ReadLine();
Console.WriteLine("End");
}
I open it thanks to Process.Start in a Form like this :
private void button1_Click(object sender, EventArgs e)
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.FileName = myexe;
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardInput = true;
processInfo.StandardOutputEncoding = Encoding.GetEncoding(850);
Process process = new Process();
process.StartInfo = processInfo;
process.Start();
}
I managed to read output using a StreamReader and get this into a textbox :
Beginning
End
But the problem is the program doesn't wait at Console.ReadLine(), like it is ignored. And i don't know how to let the user input from keyboard (better if it's directly in the console).
Is there a way to do it ?
EDIT
Looks like i wasn't clear enough, sorry.
I'm trying to make a simple Form, with no control, able to "react" when i scan a barcode.
Basically, i want the console application to run background so when my barcode is scanned, i can get it as my output value :
Form "Please scan your barcode"
Console app is launched
Barcode is scanned
Console app close
Barcode as output value
So StandardInput doesn't seems to be the solution for my problem.
That's why i'm asking you if there is a way to achieve this.
I am not quite sure what kind of problem you are facing, but I'm noticing that you aren't utilizing the StandardInput and StandardOutput properties of the Process instance (which is what you should be doing after redirecting them). See if the following example helps you.
If you have this console application:
static void Main(string[] args)
{
Console.WriteLine("Beginning");
var str = Console.ReadLine();
Console.WriteLine("End: " + str);
}
And you invoke it through this:
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = "console_program",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
};
Process process = new Process
{
StartInfo = processInfo,
};
process.Start();
process.StandardInput.WriteLine("Hey!");
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
You will get the output value:
"Beginning\r\nEnd: Hey!\r\n"

Catching runtime exceptions and outputs from python script in c#

I'm writing a WCF service which runs python scripts.
For That I've been using the following code:
ProcessStartInfo start = new ProccessStartInfo();
start.FileName = "my/full/path/to/python.exe";
start.Arguments = string.Format("{0} {1}", script, args);
start.UseShellExecute = false;
start.CreateNoWindow = true;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
Process p = new Process();
p.StartInfo = start;
p.Start();
p.WaitForExit();
string stderr = Process.StandardError.ReadToEnd();
string stdout = Process.StandardOutput.ReadToEnd();
Now what I've noticed (After a lot of testing) is that the Process object gets the Standard Error/Output or catches an exception if the error is related to "Compilation" errors, like if I have an undeclared variable used or stuff like that, but runtime exceptions and prints are not being caught or able to be read in the C# scope.
I've tried to run either the whole "python.exe pythonCommand.py args" as they are sent from the C# code or just send what was in the ProcessStartInfo.Arguments in the Command Line Prompt and it returned exceptions and prints in both cases, but still when I run it via the C# Process object I get no exceptions thrown at me to catch and no output or error what so ever.
I've found nothing about this which makes me feel kind of stupid (hopefully I am and this has a simple solution), and I would really appreciate if someone that has stumbled upon this case could help me out.
Thanks,
Matt
Well, to answer your comment here:
But the problem is both the Exception not being thrown from the the
python nor an output to be read. The Standard Output of the process
(and the Standard Error as well) are always empty – Matt Star
You are capturing the output wrong. This will allow you to capture the output and should show any exceptions thrown.
using System;
using System.Diagnostics;
namespace InteractWithConsoleApp
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
cmdStartInfo.FileName = #"C:\Windows\System32\cmd.exe";
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = true;
Process cmdProcess = new Process();
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.OutputDataReceived += cmd_DataReceived;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginOutputReadLine();
cmdProcess.BeginErrorReadLine();
cmdProcess.StandardInput.WriteLine("ping www.bing.com"); //Execute ping bing.com
cmdProcess.StandardInput.WriteLine("exit"); //Execute exit.
cmdProcess.WaitForExit();
}
static void cmd_DataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Output from other process");
Console.WriteLine(e.Data);
}
static void cmd_Error(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Error from other process");
Console.WriteLine(e.Data);
}
}
}
I copied the code from this post: How to parse command line output from c#?
I have used this method many times and it works perfect.
Hope this helps.

Problems getting desired output from Process.Start()

I am working on an application that calls several command line applications to do some post processing on some video files.
Right now I am trying to use Comskip to identify the commercial breaks in a video recording from my cable card tuner. This runs just fine, but I am having problems getting the screen output that I need.
String stdout = null;
using (var process = new Process())
{
var start = new ProcessStartInfo(comskip, cmdLine);
start.WindowStyle = ProcessWindowStyle.Normal;
start.CreateNoWindow = true;
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
process.StartInfo = start;
process.Start();
process.WaitForExit();
stdout = process.StandardOutput.ReadToEnd();
}
I'm expecting stdout to grab what is displayed on the screen the same as when the application is launched manually (screen shot below) which is a continuous feed of what the application is doing, and mixed in the output are lines that give a % progress, which I want to use to update a progress bar
But running the above code only gives me:
The commandline used was:
"C:\Users\Chris\Google Drive\Tools\ComSkip\comskip.exe" "C:\Users\Chris\Desktop\ComSkip Tuning Files\Modern Family.wtv" "--ini=C:\Users\Chris\Desktop\ComSkip Tuning Files\comskip_ModernFamily.ini"
Setting ini file to C:\Users\Chris\Desktop\ComSkip Tuning Files\comskip_ModernFamily.ini as per commandline
Using C:\Users\Chris\Desktop\ComSkip Tuning Files\comskip_ModernFamily.ini for initiation values.
I also tried redirecting the StandardError stream and grabbing process.StandardError.ReadToEnd(); but the process appears to hang if I run with these options.
Am I missing something to capture what I'm hoping for, or is it possible that the output stream for this application is going somewhere else that is not accessible?
You must set following:
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.OutputDataReceived += new DataReceivedEventHandler(ReadOutput);
process.ErrorDataReceived += new DataReceivedEventHandler(ErrorOutput);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
and catch the output in ReadOutput and ErrorOutput
private static void ErrorOutput(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
stdout = "Error: " + e.Data;
}
}
private static void ReadOutput(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
stdout = e.Data;
}
}
See the docs on RedirectStandardOutput. Waiting for the child process to end before reading the output can cause a hang.
It particular, the example says not to do what you have done:
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
You should use the events OutputDataReceived and possibly ErrorDataReceived and update the progress bar in the handler.

Executing "java -version" programmatically places the output in StandardError instead of StandardOutput

I am facing very strange behavior as I am trying to programmatically detect the java version on my PC. I am using the following C# code:
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c java -version");
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
output = proc.StandardOutput.ReadToEnd();
if (output == "")
output = proc.StandardError.ReadToEnd();
return output;
This displays the correct information but the result is found in proc.StandardError.ReadToEnd() instead of proc.StandardOutput.ReadToEnd() as in any other command (i.e. 'java -help').
Even more weird, if I run "java -showversion" which should output both java version and then help information I get the help info in the StandardOutput and the version info is in the StandardError.
This doesn't make sense to me.
I tested this on 2 Windows 7 x64 machines and 1 XP x32. Same thing everywhere. It's really weird.
Looks likes this (i.e. version being printed on standard out) is an old issue that sun (oracle) has never fixed in order to avoid breaking legacy systems: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4380614. On linux, java -version > foo will create an empty file while java -version 2> foo will create a file containing the version.
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c java -version");
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.EnableRaisingEvents = true;
// create event and wait for data receive
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
static void proc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
string s = e.Data;
}
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
string s = e.Data;
}
This should do the trick:
java -version 2>&1 | more
"more" is not required, unless you want to redirect it to file for example.
Works both on *NIX and Win.

Categories