Not able to get output messages from application when executed from c# - c#

I have a executable called background.exe which contains a c program which generates some output to the console window when executed using command prompt.
But now I want to show the output of the background.exe in c# winform application textbox.
I created a cmd process and called the background.exe but it does not display output created by the c program in the textbox. If I input commands like "Dir" then output is displayed. Please help.
Process cmdProcess;
StreamWriter cmdStreamWriter;
cmdOutput = new StringBuilder("");
cmdProcess = new Process();
cmdProcess.StartInfo.FileName = "cmd.exe";
cmdProcess.StartInfo.UseShellExecute = false;
cmdProcess.StartInfo.CreateNoWindow = true;
cmdProcess.StartInfo.RedirectStandardOutput = true;
cmdProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmdProcess.StartInfo.RedirectStandardInput = true;
cmdProcess.Start();
cmdStreamWriter = cmdProcess.StandardInput;
cmdProcess.BeginOutputReadLine();
cmdStreamWriter.WriteLine("start background.exe");
}
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
private void SortOutputHandler(object sendingProcess,
DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{
cmdOutput.Append(Environment.NewLine + outLine.Data);
SetText(cmdOutput.ToString());
}
}

Your program is basically correct. dir causes cmd.exe to print output, which your program captures. start causes cmd.exe to open a process with a new console, with the output not wired into cmd.exe for it then to relay to your program. Those are material differences. Don't use start, and you should have more luck. Also be sure to flush frequently in background.exe in case you have more problems. Finally I don't understand any of your crazy code for setting the text. I used this instead:
cmdOutput.Append(Environment.NewLine + outLine.Data);
var str = cmdOutput.ToString();
textBox1.Invoke((MethodInvoker)delegate { textBox1.Text = str; });

Related

Read Data from Process Output from SQLPlus in C# / Exits afterwards

I just asked for the Input and now I have to ask for the Output. This already worked, but apparently I changed something important.
I want to read the Output of an SqlPlus Process. The reading itself works, but then it exits further Execution.
I am using DI, but it doesn´t work within a single class either.
Program.cs:
builder.Services.AddScoped<IExecuter,ShellExecuter>();
ShellExecuter.cs:
private List<string> _commands = new List<string>();
private Process _process;
private ProcessStartInfo _startInfo;
public ShellExecuter(){
_startInfo = new ProcessStartInfo();
_startInfo.WorkingDirectory = Path.GetTempPath();
_startInfo.FileName = "sqlplus.exe";
_startInfo.UseShellExecute = false;
_startInfo.RedirectStandardOutput = true;
_startInfo.RedirectStandardError = true;
_startInfo.RedirectStandardInput = true;
_startInfo.CreateNoWindow = true;
_process = new Process();
}
public void Start()
{
_startInfo.Arguments = $"-s user/pass#db";
_process.StartInfo = _startInfo;
// _process.EnableRaisingEvents = true;
_process.Start();
_process.ErrorDataReceived += (sender, args) =>
{
System.Diagnostics.Debug.WriteLine("Error: " + args.Data);
};
process.Exited += new System.EventHandler(Exited);
}
...Methods to add to _commands and Write them.
public string Output()
{
string line = "";
while (!_process.StandardOutput.EndOfStream)
{
line += _process.StandardOutput.ReadLine();
System.Diagnostics.Debug.WriteLine("Output: " + line);
}
}
HomeController.cs:
public IActionResult Index(IExecuter exec)
{
exec.Start();
exec.AddCommand(" create or replace view testview(ID) as select ID from
MyUSER;");
exec.Execute();
var output = exec.Output();
return Content(output);
}
So, when I run this it properly creates the View and goes into the Output loop. However, after I get the "Output: View created.", it will take ~1s and then I will get the message "The Thread xxxxx has exited with Code 0"
I am not sure if this exit is about the Process or the ShellExecuter, but I don´t get out of the While Loop anymore and the Debugger does not show the Buttons to jump to the next Line anymore. Nor does the Website update.
What do I overlook here? It already worked...
In order to read the output you need to attach to the event like this
_process.OutputDataReceived += new DataReceivedEventHandler(DataReceived);
with a method like this
public StringBuilder Output = new StringBuilder();
void DataReceived(object sender, DataReceivedEventArgs e)
{
Output.AppendLine(e.Data);
}
then also add this
_process.Start();
_process.WaitForExit(); //very important!
then you can call
var output = exec.Output.ToString();

C# Redirect other console app StandardOutput fail if I won't close StardandInput

I've got a tricky issue with a console app, from which I'm trying to redirect StandardInput, StandardOutput and StandardError.
I've got a working solution for other console app - that's not a new thing for me. But this app seems to have something special, which is making impossible to redirect all outputs with a standard approach.
Console app works like this:
directly after startup writes a few lines and waits for user input
no matter what input is - console app is showing some output and again wait for new input
console app never ends, it has to be closed
I've tried already solutions based on:
StandardOutput/Error.ReadToEnd()
taki care of OutputDataReceived & ErrorDataReceived with read line by line with ReadLine
reading by char
waiting for the end of process (which is not ending, so I'm running into a deadlock)
to start console app in a preloaded cmd.exe and grab this (StandardOutput stopped to show just after launch of this console app)
to manually flush input
All the time I had completely no output and no error stream from console app - nothing.
After a multitude attempts I've discovered, that I can receive StandardOutput only when I'll close StandardInput after programatically inputting the data.
But in this case, console app is going wild, falling into loop of writing few lines to StandardOutput as on start-up, which makes final output big and full of garbages.
With MedallionShell library I'm able to try to gracefully kill it with Ctrl+C, but this solution is still far from acceptable, because:
sometimes console app will produce so much garbages before I will be able to kill it, that it crashes my app
even if this won't crash, searching for expected output in a lot of garbages is nasty and tragically slows down automatization (6000 records in... 15 minutes)
I'm unable to provide more than one input at a time, so I have to start console app just to receive one output, close and start again for another output
I've got no sources for that console app, so I'm even not able to recreate the issue or fix it - it's some very legacy app at my company, which I'm trying to make at least a bit automatic...
Code, with which I've got at least anything now (with MediallionShell):
var command = Command.Run(Environment.CurrentDirectory + #"\console_app.exe");
command.StandardInput.WriteLine("expected_input");
command.StandardInput.Close(); // without that I'll never receive any output or error stream from this stubborn console app
command.TrySignalAsync(CommandSignal.ControlC); // attempt to kill gracefully, not always successfull...
var result = command.Result;
textBox1.AppendText(String.Join(Environment.NewLine, command.GetOutputAndErrorLines().ToArray().Take(10))); // trying to get rid of garbages
command.Kill(); // additional kill attempt if Ctrl+C didn't help, sometimes even this fails
Any help will be appreciated, I'm also still searching for solution and now I'm checking this one: PostMessage not working with console window whose output is redirected and read asynchronously but author there had an output and I don't...
You haven't provided a sample Console program to test with, but something like the following may work:
Create a Console project (Console (.NET Framework)) - used for testing
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleTestApp
{
class Program
{
static void Main(string[] args)
{
//prompt for input - 1st prompt
Console.Write("Please enter filename: ");
string filename = Console.ReadLine();
if (System.IO.File.Exists(filename))
{
Console.WriteLine("'" + filename + "' exists.");
}
else
{
Console.Error.WriteLine("'" + filename + "' doesn't exist.");
}
//prompt for input - 2nd prompt
Console.Write("Would you like to exit? ");
string answer = Console.ReadLine();
Console.WriteLine("Your answer was: " + answer);
Console.WriteLine("Operation complete.");
}
}
}
Then, create a Windows Forms project Windows Forms (.NET Framework) and run one of the following:
Option 1:
private void RunCmd(string exePath, string arguments = null)
{
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(exePath, arguments);
startInfo.Arguments = arguments; //arguments
startInfo.CreateNoWindow = true; //don't create a window
startInfo.RedirectStandardError = true; //redirect standard error
startInfo.RedirectStandardOutput = true; //redirect standard output
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false; //if true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
//create new instance
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
//subscribe to event and add event handler code
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Output: " + e.Data);
}
};
p.Start(); //start
p.BeginErrorReadLine(); //begin async reading for standard error
p.BeginOutputReadLine(); //begin async reading for standard output
using (StreamWriter sw = p.StandardInput)
{
//provide values for each input prompt
//ToDo: add values for each input prompt - changing the for loop as necessary
for (int i = 0; i < 2; i++)
{
if (i == 0)
sw.WriteLine(#"C:\Temp\Test1.txt"); //1st prompt
else if (i == 1)
sw.WriteLine("Yes"); //2nd prompt
else
break; //exit
}
}
//waits until the process is finished before continuing
p.WaitForExit();
}
}
Option 2:
private void RunCmd(string exePath, string arguments = null)
{
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(exePath, arguments);
startInfo.Arguments = arguments; //arguments
startInfo.CreateNoWindow = true; //don't create a window
startInfo.RedirectStandardError = true; //redirect standard error
startInfo.RedirectStandardOutput = true; //redirect standard output
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false; //if true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
//create new instance
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
//subscribe to event and add event handler code
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Output: " + e.Data);
}
};
p.Start(); //start
p.BeginErrorReadLine(); //begin async reading for standard error
p.BeginOutputReadLine(); //begin async reading for standard output
using (StreamWriter sw = p.StandardInput)
{
//provide values for each input prompt
//ToDo: add values for each input prompt - changing the for loop as necessary
sw.WriteLine(#"C:\Temp\Test1.txt"); //1st prompt
sw.WriteLine("Yes"); //2nd prompt
}
//waits until the process is finished before continuing
p.WaitForExit();
}
}
Option 3:
Note: This one is modified from here.
private void RunCmd(string exePath, string arguments = null)
{
//create new instance
ProcessStartInfo startInfo = new ProcessStartInfo(exePath, arguments);
startInfo.Arguments = arguments; //arguments
startInfo.CreateNoWindow = true; //don't create a window
startInfo.RedirectStandardError = true; //redirect standard error
startInfo.RedirectStandardOutput = true; //redirect standard output
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false; //if true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.ErrorDialog = false;
//create new instance
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
p.Start(); //start
Read(p.StandardOutput);
Read(p.StandardError);
using (StreamWriter sw = p.StandardInput)
{
//provide values for each input prompt
//ToDo: add values for each input prompt - changing the for loop as necessary
sw.WriteLine(#"C:\Temp\Test1.txt"); //1st prompt
sw.WriteLine("Yes"); //2nd prompt
}
//waits until the process is finished before continuing
p.WaitForExit();
}
}
private static void Read(StreamReader reader)
{
new System.Threading.Thread(() =>
{
while (true)
{
int current;
while ((current = reader.Read()) >= 0)
Console.Write((char)current);
}
}).Start();
}

Duplicate process start doesn't react as expected

i'm trying to open a process with c# and react to it, when it's been closed. This work's for me:
private void StartProc()
{
var process = new System.Diagnostics.Process { StartInfo = { FileName = "PathTo.exe" } };
process.Start();
process.EnableRaisingEvents = true;
process.Exited += this.Editor_Exited;
}
private void Editor_Exited(object sender, EventArgs e)
{
MessageBox.Show("Process canceled");
}
Lets say I'm opening a text editor with this code. If there is already an instance of this text editor the code won't open a second instance and also jumps instant in the Editor_Exited Code.
I want the code to open a new instance and don't jump in the Editor_Exited code.
string processName = "PathTo.exe";
var process = new System.Diagnostics.Process { StartInfo = { FileName = processName } };
if (process.Start())
{
process.EnableRaisingEvents = true;
process.Exited += this.Editor_Exited;
}
else
{
var p = Process.GetProcessesByName(processName);
p.WaitForExit();
}
I get this is not 100% what you are asking for, but its a work around

How can I redirect process output (console) to richtextbox?

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.
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());
}
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
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
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.
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.

Capturing console output from a .NET application (C#)

How do I invoke a console application from my .NET application and capture all the output generated in the console?
(Remember, I don't want to save the information first in a file and then relist as I would love to receive it as live.)
This can be quite easily achieved using the ProcessStartInfo.RedirectStandardOutput property. A full sample is contained in the linked MSDN documentation; the only caveat is that you may have to redirect the standard error stream as well to see all output of your application.
Process compiler = new Process();
compiler.StartInfo.FileName = "csc.exe";
compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs";
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.Start();
Console.WriteLine(compiler.StandardOutput.ReadToEnd());
compiler.WaitForExit();
This is bit improvement over accepted answer from #mdb. Specifically, we also capture error output of the process. Additionally, we capture these outputs through events because ReadToEnd() doesn't work if you want to capture both error and regular output. It took me while to make this work because it actually also requires BeginxxxReadLine() calls after Start().
Asynchronous way:
using System.Diagnostics;
Process process = new Process();
void LaunchProcess()
{
process.EnableRaisingEvents = true;
process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
process.Exited += new System.EventHandler(process_Exited);
process.StartInfo.FileName = "some.exe";
process.StartInfo.Arguments = "param1 param2";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
//below line is optional if we want a blocking call
//process.WaitForExit();
}
void process_Exited(object sender, EventArgs e)
{
Console.WriteLine(string.Format("process exited with code {0}\n", process.ExitCode.ToString()));
}
void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data + "\n");
}
void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data + "\n");
}
Use ProcessStartInfo.RedirectStandardOutput to redirect the output when creating your console process.
Then you can use Process.StandardOutput to read the program output.
The second link has a sample code how to do it.
ConsoleAppLauncher is an open source library made specifically to answer that question. It captures all the output generated in the console and provides simple interface to start and close console application.
The ConsoleOutput event is fired every time when a new line is written by the console to standard/error output. The lines are queued and guaranteed to follow the output order.
Also available as NuGet package.
Sample call to get full console output:
// Run simplest shell command and return its output.
public static string GetWindowsVersion()
{
return ConsoleApp.Run("cmd", "/c ver").Output.Trim();
}
Sample with live feedback:
// Run ping.exe asynchronously and return roundtrip times back to the caller in a callback
public static void PingUrl(string url, Action<string> replyHandler)
{
var regex = new Regex("(time=|Average = )(?<time>.*?ms)", RegexOptions.Compiled);
var app = new ConsoleApp("ping", url);
app.ConsoleOutput += (o, args) =>
{
var match = regex.Match(args.Line);
if (match.Success)
{
var roundtripTime = match.Groups["time"].Value;
replyHandler(roundtripTime);
}
};
app.Run();
}
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)
I made a reactive version that accepts callbacks for stdOut and StdErr.
onStdOut and onStdErr are called asynchronously,
as soon as data arrives (before the process exits).
public static Int32 RunProcess(String path,
String args,
Action<String> onStdOut = null,
Action<String> onStdErr = null)
{
var readStdOut = onStdOut != null;
var readStdErr = onStdErr != null;
var process = new Process
{
StartInfo =
{
FileName = path,
Arguments = args,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = readStdOut,
RedirectStandardError = readStdErr,
}
};
process.Start();
if (readStdOut) Task.Run(() => ReadStream(process.StandardOutput, onStdOut));
if (readStdErr) Task.Run(() => ReadStream(process.StandardError, onStdErr));
process.WaitForExit();
return process.ExitCode;
}
private static void ReadStream(TextReader textReader, Action<String> callback)
{
while (true)
{
var line = textReader.ReadLine();
if (line == null)
break;
callback(line);
}
}
Example usage
The following will run executable with args and print
stdOut in white
stdErr in red
to the console.
RunProcess(
executable,
args,
s => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(s); },
s => { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(s); }
);
From PythonTR - Python Programcıları Derneği, e-kitap, örnek:
Process p = new Process(); // Create new object
p.StartInfo.UseShellExecute = false; // Do not use shell
p.StartInfo.RedirectStandardOutput = true; // Redirect output
p.StartInfo.FileName = "c:\\python26\\python.exe"; // Path of our Python compiler
p.StartInfo.Arguments = "c:\\python26\\Hello_C_Python.py"; // Path of the .py to be executed
Added process.StartInfo.**CreateNoWindow** = true; and timeout.
private static void CaptureConsoleAppOutput(string exeName, string arguments, int timeoutMilliseconds, out int exitCode, out string output)
{
using (Process process = new Process())
{
process.StartInfo.FileName = exeName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
output = process.StandardOutput.ReadToEnd();
bool exited = process.WaitForExit(timeoutMilliseconds);
if (exited)
{
exitCode = process.ExitCode;
}
else
{
exitCode = -1;
}
}
}

Categories

Resources