I have a console application and try to use it in C# Asp.Net Core 3.1 WebApi application. The code I am using is as follow:
Create process
Process process;
process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.FileName = executable;
process.Start();
Then I keep using the following code to send command to the console application and read the output
process.StandardInput.WriteLine(argument);
string output = string.Empty;
do
{
Thread.Sleep(50);
output = process.StandardOutput.ReadLine();
} while (output == null);
The result is, for the first a few commands, I can get the result from ReadLine function correctly. However, after a few commands, I keep getting null and the whole application stuck at the while loop.
I ran the console application in console and send commands one by one that feed into the second step and all of them can return correct result and print the results in the console as expected.
Can anyone help what could be wrong? Thank you
i just created the solution with your aproach and everything is working correctly. I would advise you to use rather await Task.Delay(50) than Thread.Sleep(50) So having two such console application. Firstly the application i will want to call (i am calling it "External" one:
static void Main(string[] args)
{
string key = String.Empty;
do
{
key = Console.ReadLine();
Console.WriteLine($"{key} was pressed in external program");
} while (key != "q");
}
and the application that is calling this method:
static async Task Main(string[] args)
{
using (Process process = new Process())
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.FileName = #"[path_to_the_previous_console_app]\TestConsoleAppExternal.exe";
process.Start();
Console.WriteLine("Write some key");
string key = String.Empty;
do
{
key = Console.ReadLine();
await Interact(process, key);
} while (key != "q");
}
}
static async Task Interact(Process process, string argument)
{
process.StandardInput.WriteLine(argument);
string output = string.Empty;
do
{
await Task.Delay(50);
output = process.StandardOutput.ReadLine();
} while (output == null);
Console.WriteLine($"{argument} was pressed from Main process and readed output was: '{output}' ");
}
And everything works as designed. What scenario exactly you want to achieve? What kind of application are you calling? Maybe this is the difference?
Related
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();
}
I want to run process in SQL Server CLR this my code:
[SqlProcedure]
private static int RunExecutable()
{
SqlDataRecord sqlDataRecord = new SqlDataRecord(new SqlMetaData("message", SqlDbType.NVarChar, 1L));
SqlContext.Pipe.SendResultsStart(sqlDataRecord);
int lineCount = 0;
Process process = new Process();
process.StartInfo.FileName = "ipconfig.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.EnableRaisingEvents = true;
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
sqlDataRecord.SetString(0, "OnDataReceived");
SqlContext.Pipe.SendResultsRow(sqlDataRecord);
if (!String.IsNullOrEmpty(e.Data))
{
lineCount++;
sqlDataRecord.SetString(0, "[" + lineCount + "]: " + e.Data);
SqlContext.Pipe.SendResultsRow(sqlDataRecord);
}
});
process.Start();
process.BeginOutputReadLine();
while (!process.HasExited)
{
sqlDataRecord.SetString(0, "process WaitForExit ");
SqlContext.Pipe.SendResultsRow(sqlDataRecord);
process.WaitForExit(300);
}
}
and ipconfig.exe runs (I see in results "process WaitForExit"), but the OutputDataReceived event is not triggered.
The assembly was created in SQL Server 2019 Enterprise with PERMISSION_SET = UNSAFE;. If I run the same code as the standard console application everything works fine
That's going to require a background thread to run the event while you block the session's thread on WaitForExit. I'm not surprised it doesn't work in SQLCLR, which is a very different .NET Framework host than a console application.
And even if the event fires, you could not access SqlContext.Pipe from a thread other than the thread that called into the method.
Instead perform blocking reads of StandardOutput using the thread that called into your method, like this:
static IEnumerable<string> GetOutputLines(string exeName, string args = null)
{
Process process = new Process();
process.StartInfo.FileName = exeName;
process.StartInfo.Arguments = args;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.EnableRaisingEvents = true;
process.Start();
while ( true )
{
var line = process.StandardOutput.ReadLine();
if (line == null)
break;
yield return line;
}
process.WaitForExit();
}
+1 to David for answering the general question of how to best capture and return command-line output.
However, for your specific scenario of running ipconfig.exe and returning all of the output, I think you would be far better served by simply using:
NetworkInterface.GetAllNetworkInterfaces()
I would try that first. This might require you to load the System.Net.NetworkInformation.dll Framework library as UNSAFE in the same database, but you are already doing "unsafe" operations by shelling out to the OS, so at least this is handled in managed code.
I am trying to implement piping behavior in C#.NET using Process and ProcessStartInfo classes. My intention is to feed the output of previous command to next command so that that command will process the input and return result. have a look into following code -
private static string Out(string cmd, string args, string inputFromPrevious)
{
string RetVal = string.Empty;
try
{
ProcessStartInfo psi = String.IsNullOrEmpty(args) ? new ProcessStartInfo(cmd) : new ProcessStartInfo(cmd, args);
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.RedirectStandardInput = string.IsNullOrEmpty(inputFromPrevious) ? false : true;
Process proc = new System.Diagnostics.Process();
proc.StartInfo = psi;
if (proc.Start())
{
if (!string.IsNullOrEmpty(inputFromPrevious))
{
proc.StandardInput.AutoFlush = true;
proc.StandardInput.WriteLine(inputFromPrevious); proc.StandardInput.WriteLine();
proc.StandardInput.Close();
}
using (var output = proc.StandardOutput)
{
Console.WriteLine("3. WAITING WAITING....."); < ---Code halts here.
RetVal = output.ReadToEnd();
}
}
proc.WaitForExit();
proc.Close();
}
catch (Exception Ex)
{
}
return RetVal; < ---This is "inputFromPrevious" to next call to same function
}
I am calling above code in loop for different commands and arguments. Is there any mistake in my code? I had looked similar as shown below but nothing worked for me as of now. Any help will be appreciated.
Piping in a file on the command-line using System.Diagnostics.Process
Why is Process.StandardInput.WriteLine not supplying input to my process?
Repeatably Feeding Input to a Process' Standard Input
I'm writing an AIR app that launches a C# console application and they need to communicate. I'd like to use standard input/standard output for this, however I can't seem to get it to work.
When the C# app gets input from standard input it's supposed to send it back via standard output, and if it receives "exit" then it quits. I can test this from the command line and it works correctly. When I send a string from AIR, I get no response from the C# app.
I'm sending an argument when I launch the C# app, and I do get a response from that, so my AIR app is at least able to receive messages from standard output, it's just standard input that is not working. When I send a message from AIR via standardInput I get a progress event with bytesLoaded = 3 when I send the keycode, and bytesLoaded = 5 when I send the "exit" command.
Here is the C# code:
static void Main(string[] args)
{
if (args.Length > 0)
{
Console.WriteLine(args[0]);
}
while (true)
{
string incoming = Console.ReadLine();
string outgoing = "received: " + incoming;
Console.WriteLine(outgoing);
if (incoming == "exit")
return;
}
}
And here is the AS3 code:
private function init(e:Event=null):void {
this.removeEventListener(Event.ADDED_TO_STAGE, init);
NativeApplication.nativeApplication.addEventListener(Event.EXITING, onAppClose);
var info:NativeProcessStartupInfo = new NativeProcessStartupInfo();
var file:File = File.applicationDirectory.resolvePath("test.exe");
info.executable = file;
process = new NativeProcess();
info.arguments.push("native process started");
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onErrorData);
process.addEventListener(ProgressEvent.STANDARD_INPUT_PROGRESS, onInputProgress);
process.addEventListener(Event.STANDARD_OUTPUT_CLOSE, onOutputClose);
process.addEventListener(Event.STANDARD_ERROR_CLOSE, onErrorClose);
process.addEventListener(IOErrorEvent.STANDARD_ERROR_IO_ERROR, onIOError);
process.addEventListener(IOErrorEvent.STANDARD_INPUT_IO_ERROR, onIOError);
process.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, onIOError);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
process.start(info);
}
private function onKeyUp(e:KeyboardEvent):void {
if (e.keyCode == Keyboard.ESCAPE)
process.standardInput.writeUTFBytes("exit\n");
else {
var msg:String = e.keyCode + "\n";
process.standardInput.writeUTFBytes(msg);
}
}
private function onOutputData(e:ProgressEvent):void {
var data:String = process.standardOutput.readUTFBytes(process.standardOutput.bytesAvailable);
trace("Got: ", data);
}
I encountered this issue a few months back but I never resolved it as I just used command line args instead. I have just returned to it though as I am keen to find out know what's going on.
I have now found that targeting .NET 3.5 or earlier makes it work as expected for me. Switch back to to v4.0 and I get nothing on stdin. I'm not exactly sure where the issue lies, but if you can get by with v3.5 then it might be a solution for you.
In case anyone else besides me still use Adobe AIR with C# console apps, here's a solution to the problem:
Just like #tom-makin points out in the linked answer, you need to create another console app that runs on .NET 3.5, which then opens your newer .NET console app and passes input to it. Here's my take on such an app:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace StdInPiper
{
class Program
{
static void Main(string[] args)
{
// Remove the first arg from args, containing the newer .NET exePath.
string exePath = args[0];
var tempArgs = new List<string>(args);
tempArgs.RemoveAt(0);
string argsLine = "";
foreach (string arg in tempArgs)
{
argsLine = argsLine + " " + arg;
}
argsLine = argsLine.Trim();
var process = new Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.Arguments = argsLine;
process.StartInfo.FileName = exePath;
process.OutputDataReceived += (sender, eventArgs) =>
{
Console.Write(eventArgs.Data);
};
process.ErrorDataReceived += (sender, eventArgs) =>
{
Console.Error.Write(eventArgs.Data);
};
process.Exited += (sender, eventArgs) =>
{
process.CancelOutputRead();
process.CancelErrorRead();
Environment.Exit(Environment.ExitCode);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
while (true)
{
Thread.Sleep(20);
string line = Console.ReadLine();
if (line != null)
{
process.StandardInput.WriteLine(line);
}
}
}
}
}
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;
}
}
}