How do I run processes synchronously, targeting the same output? - c#

I have a .Net application that needs to run several executables. I'm using the Process class, but Process.Start doesn't block. I need the first process to finish before the second runs. How can I do this?
Also, I'd like all of the processes to all output to the same console window. As it is, they seem to open their own windows. I'm sure I can use the StandardOutput stream to write to the console, but how can I suppress the default output?

I believe you're looking for:
Process p = Process.Start("myapp.exe");
p.WaitForExit();
For output:
StreamReader stdOut = p.StandardOutput;
Then you use it like any stream reader.
To suppress the window it's a bit harder:
ProcessStartInfo pi = new ProcessStartInfo("myapp.exe");
pi.CreateNoWindow = true;
pi.UseShellExecute = true;
// Also, for the std in/out you have to start it this way too to override:
pi.RedirectStandardOutput = true; // Will enable .StandardOutput
Process p = Process.Start(pi);

Related

Run C# Console application in WinForms Application and Wait till it completes

I have a C# Console application which I am trying to execute from another WinForm application just like batch runner by giving the console application's .exe file like below.
Process.Start("Path of Console application exe to execute")
However I need to wait and handle the output and display the output in WinForm's richtextbox from console application once it has completed the execution. How can I achieve this?
Update
I have changed the code to Start a Process and Read using StandardOutput and BeginOutputReadLine() to Read the output asynchronously, but not able to see output in console window, instead console window is getting closed. Not sure how to solve this.
p.StartInfo.UseShellExecute = false;
// p.StartInfo.CreateNoWindow = True
p.StartInfo.RedirectStandardOutput = true;
string #out = null;
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
#out += e.Data;
});
p.StartInfo.FileName = currentTest;
p.Start();
p.BeginOutputReadLine();
// string output = p.StandardError.ReadToEnd();
// p.WaitForExit()
while (!p.HasExited)
Application.DoEvents();
//Console.WriteLine($#"Output \n'{output.Substring(output.Length - 50)}'");
Console.WriteLine($#"\n Error stream: {#out}");
Console.ReadLine();
You need to redirect stdout (and probably stderr) so that any output comes to you, instead of a console; you may also want to redirect stdin. All of these things are available via ProcessStartInfo, with an example on MSDN. Note that if you want to display updates while the exe is running, you may need a worker thread to read incrementally from StandardOutput and StandardError, rather than ReadToEnd() - which won't return anything at all until the associated output pipe is closed.
However! If the console exe is "yours", it may be simpler to just expose the functionality you want in a library, and invoke it directly in-process. There are times when out-of-process is actively preferred, such as when you need to allow that process to go catastrophically wrong in some scenarios - but usually in-process is preferable, given free rein.

c# How to redirect stdout to new process window?

I was creating a Process using the call:
Process.Start(startInfo);
with
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.FileName = "cmd.exe";
startInfo.UseShellExecute = true;
startInfo.RedirectStandardInput = false;
startInfo.RedirectStandardOutput = false;
when the process runs with these arguments, it outputs to the new process's window fine.
However, when I make UseShellExecute false without redirecting standard output, the process no longer prints to the screen. Is this the expected behavior?
If so, how can i write to the new window that the process starts?
I can manually get the data from the process using StandardOutput.Read(), but I don't know how to write that to the new window. When I create that window, it appears to have a console by default.
I can use pinvoke to call the C++ function on the new process:
[DllImport("kernel32", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
I think that I may be able to just write to the console of the new window using the function "writeconsole"
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687401%28v=vs.85%29.aspx
however, i was wondering if it's possible to do this just using .net libraries. I feel like what I want isn't so complicated that this should be necessary.
All I want is to be able to start a new process and redirect the stdout of that process to the new window that is created in that process, while retaining the ability to write to stdin.
edit:
Writing using console.writeline would just write to the main console of the program. My application is a gui app, so to be honest, I don't know exactly where it writes to, but I do know that you can see this output under the tab "output" in visual studio but not in the windows of the program itself. I think that there is a separate buffer allocated by .net for the console.
You can redirect stdout and stdin with freopen.
Example:
freopen ("file.txt","w", stdout); //or stdin
EDIT:
You could also use createpipe() and read from the end of the pipe. You can tell the pipe, then, where you would like your data to be read to or stored/displayed. If this is not what you are looking for, please elaborate more in depth with a comment.

Reading StdOut after process has been abnormally terminated using Process.kill

i am invoking an exe via c# Diagnostics.Process class and read output from it's StdOut. The process is forcefully terminated in case it doesn't automatically terminates in a specified time, something like:
process.StartInfo.FileName = #"D:\t.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
process.WaitForExit(500);
if (!process.HasExited)
{
process.Kill();
process.WaitForExit();
}
string stdOutContents = process.StandardOutput.ReadToEnd();
Now the problem is the code works succesfully when the exe terminates normally. But in case it fails to terminate normally (usually the exe gets stuck in an infinite loop somewhere), stdOutContents is read as an empty string.
How can i read StdOut after the process is killed (without using process.OutputDataReceived event technique)? (It has been verified that the exe-in-question does always writes something onto StdOut even if it gets stuck somewhere).
Update 1
Details about Exe which is being invoked (refereed as 'native app' across this question)
It is a small utility implemented in c language and compiled using MS C++ compiler. It does its job while simultaneously outputting status information onto the StdOut (using putchar).
There are only two possible cases of operation:
It will run successfully while simultaneously printing some data onto the StdOut.
It will run normally to a certain point (simultaneously outputting data on StdOut) and then get stuck in an infinite loop. (This is an acceptable behavior).
Both scenarios have been verified using cmd.
Details about new attempts
i wrote a c# app (referred as dummy app) which mimics the native app behavior and this code works fine. However when run for the native app, i get nothing at all.
i don't understand why the code cant read the contents outputted by the native app?
i also tried using event handler for OutputDataReceived. It gets called only once with args.Data = null when the code tries to kill the process. Inspecting the behavior for dummy app revealed that when process.kill is called, the handler is invoked with args.Data = null. So this seems to be a standard behavior of sorts for both apps.
i also tried changing the newline characters for native app. Since it is implemented in c language, it uses \n for newline. i tried using both \r\n pair for newline but StdOut is still blank (for case 2).
I had the same interrogation and the doc of Process.Kill says
Data edited by the process or resources allocated to the process can be lost if you call Kill.
Which seems to indicate that you cannot rely on reading the StandardOutput of a process, although it is not clearly stated that the output / error streams are disposed.
I finally got inspired by this answer
How to spawn a process and capture its STDOUT in .NET?
and I use the following code :
var info = new ProcessStartInfo("some.exe");
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
using (var p = new Process())
{
p.StartInfo = info;
var output = new StringBuilder();
p.OutputDataReceived += (sender, eventArgs) =>
{
output.AppendLine(eventArgs.Data);
};
p.Start();
p.BeginOutputReadLine();
if (!p.WaitForExit(5000))
{
Console.WriteLine("Taking too long...");
p.Kill();
Console.WriteLine("Process killed, output :\n" + output);
}
}
Same pattern can be used with the ErrorDataReceived
Note that one could miss some unflushed output from the child process, however in my case I don't expect much from a process that requires to be killed, at most some information for debugging purposes.

ReadToEnd from std output of process and waitforexit

From the MSDN example of using stdoutput of newly created process:
// This is the code for the base process
Process myProcess = new Process();
// Start a new instance of this program but specify the 'spawned' version.
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(args[0], "spawn");
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
StreamReader myStreamReader = myProcess.StandardOutput;
// Read the standard output of the spawned process.
string myString = myStreamReader.ReadLine();
Console.WriteLine(myString);
myProcess.WaitForExit();
myProcess.Close();
If instead of myStreamReader.ReadLine() I'm using myStreamReader.ReadToEnd() shall I still use myProcess.WaitForExit()?
Or ReadToEnd() will wait until the process is finished?
EDIT:
Sorry for the diversion, to directly answer your question. Yes, you need to call Process.WaitForExit();. This will ensure that the process has yielded all its output before you call ReadToEnd()
ReadToEnd is synchronous function. Hence if you don't call it in your code, it will block your main thread until it captures only the first output from the StandardOutput, then that's it. But using WaitForExit will ensure that you have everything.
Also you might consider doing an asynchronous read of the process's output, see this MSDN Example that implements OutputDataRecieved
"ReadToEnd" is a function stored in "StreamReader" object and I don't think it has something to do with waiting for a process to exit, however the "Process" class might handle that itself. By the way, all the abilities "StreamReader" has are not useful in the situation you mentioned.
In my point of view, "WaitForExit" should be called and as you did "Close" too. Because they will release some system resources that no method else can. As far as I know, "ReadToEnd" method has nothing to do with calling those two.
Cheers

run console application in C# with parameters

How can I run a console application in C#, passing parameters to it, and get the result of the application in Unicode? Console.WriteLine is used in the console application.
Important point is write Unicode in Console Application.
Sample from MSDN
// Start the child process.
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();
try with below code, here "Amay" is a argument.
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(#"E:\\ConsoleApplicationt\bin\Debug\ConsoleApplicationt.exe", "Amay");
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
Check out Process.Start():
MSDN - Process.Start Method
Your code will probably look something like:
var process = Process.Start(pathToProgram, argsString);
process.WaitForExit();
var exitCode = process.ExitCode;
If by "result of the console application" you mean any output of the program to the console while it runs...you'll need to look at the documentation and figure out how to redirect the output of the program from the console to another stream.
Here http://www.aspcode.net/ProcessStart-and-redirect-standard-output.aspx You can see how to read the output from the console app You start with Process.Start().
Take a look at the Process class. You can call any executable using Process.Start("myexe.exe");
You should be careful depending upon your use some of the other examples can have issues. For common mistakes made writing your own code, read "How to use System.Diagnostics.Process correctly"
For a library to use, there is one here: http://csharptest.net/browse/src/Library/Processes
with a brief usage guide: "Using the ProcessRunner class"

Categories

Resources