This question already has answers here:
Redirect console output to textbox in separate program
(4 answers)
C# - Capturing Windows Application Output
(3 answers)
Closed 9 years ago.
In C# I am starting a 3rd party application that takes 2 - 3 hours to complete. I need the output of the Process to write to the console in real time. I have done research on BeginOutputReadLine() and RedirectStandardOutput from Microsoft's website but my code is still not working.
Currently my code is only showing the output when the process is finished. I don't know where its gone wrong.
static void Main(string[] args)
{
Process process;
process = new Process();
process.StartInfo.FileName = "C:\\ffmbc\\ffmbc.exe";
process.StartInfo.Arguments = "-i \\\\dssp-isi-t\\TMD\\B002C010_130520_R2R7.2398v5.mxf -an -vcodec libx264 -level 4.1 -preset veryslow -tune film -x264opts bluray-compat=1:weightp=0:bframes=3:nal-hrd=vbr:vbv-maxrate=40000:vbv-bufsize=30000:keyint=24:b-pyramid=strict:slices=4:aud=1:colorprim=bt709:transfer=bt709:colormatrix=bt709:sar=1/1:ref=4 -b 30M -bt 30M -threads 0 -pass 1 -y \\\\dss-isi-t\\MTPO_Transfer\\dbay\\B002C010_130520_R2R7.2398v5.mxf.h264";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
process.Close();
}
private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
string line;
line = (outLine.Data.ToString());
Console.WriteLine(line);
}
Similar to a previous question I'd answered, maybe even a duplicate.
See: Pipe a stream to Debug.Write()
Here's my answer (modified slightly) from that:
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += p_OutputDataReceived;
process.Start();
process.BeginOutputReadLine();
Then, your event handler for receiving data.
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.Write(e.Data);
}
Basically, you just need to nix the WaitForExit(), since that makes your program hang until the process completes.
The line
process.WaitForExit();
will cause the current program to wait until the given process finishes. This is most certainly not what you want; you probably want to start the process, let it run asynchronously, and then let it tell you when it finishes. For that, you will want to use the process.Exited event.
Related
This question already has answers here:
Process.start: how to get the output?
(11 answers)
ProcessStartInfo hanging on "WaitForExit"? Why?
(22 answers)
Closed 4 years ago.
I am trying to run a command in cmd.exe, and redirect the output to a textfile. I have verified that the command is being executed, but when I call StandardOutput.ReadToEnd() or StandardError.ReadToEnd(), an empty string is returned instead of the text output from the command. Am I missing something?
ProcessStartInfo PSI = new ProcessStartInfo("cmd.exe", command);
PSI.UseShellExecute = false;
PSI.CreateNoWindow = true;
PSI.RedirectStandardInput = true;
PSI.RedirectStandardOutput = true;
PSI.RedirectStandardError = true;
PSI.Arguments = "/c";
var proc = Process.Start(PSI);
proc.WaitForExit();
string output = proc.StandardOutput.ReadToEnd();
Console.WriteLine(output);
string errors = proc.StandardError.ReadToEnd();
Console.WriteLine(errors);
I'm pretty sure using ReadToEnd doesn't work if you're also capturing error output at the same time. You'll need to use proc.BeginOutputReadLine() instead (and proc.BeginErrorReadLine() for the error output).
However, those methods are asynchronous, so you'll need to use event handlers to actually get the output.
PSI.EnableRaisingEvents = true;
proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(OutputReceivedHandler);
proc.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(ErrorReceivedHandler);
The handlers have the output/error data stored in the event argument's Data property.
private void OutputReceivedHandler(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
private void ErrorReceivedHandler(object sender, ErrorReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
Since this is all asynchronous, you'll want to ditch the WaitForExit call, as that will block unnecessarily. If you do want the call to block, you can use WaitForExit, but refer to the answer that user Greg linked in the comments for an implementation that won't result in a buffer overflow.
I am currently working on a C# Program which needs to call a local PHP script and write its output to a file. The problem is, that I need to be able to stop the execution of the script.
First, I tried to call cmd.exe and let cmd write the output to the file which worked fine. But I found out, that killing the cmd process does not stop the php cli.
So I tried to call php directly, redirect its output and write it from the C# code to a file. But here the problem seems to be, that the php cli does not terminate when the script is done. process.WaitForExit() does not return, even when I am sure that the script has been fully executed.
I cannot set a timeout to the WaitForExit(), because depending on the arguments, the script may take 3 minutes or eg. 10 hours.
I do not want to kill just a random php cli, there may be others currently running.
What is the best way to call a local php script from C#, writing its output to a file and beeing able to stop the execution?
Here is my current code:
// Create the process
var process = new System.Diagnostics.Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "php.exe";
// CreateExportScriptArgument returns something like "file.php arg1 arg2 ..."
process.StartInfo.Arguments = CreateExportScriptArgument(code, this.content, this.options);
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
// Start the process or cancel, if the process should not run
if (!this.isRunning) { return; }
this.currentProcess = process;
process.Start();
// Get the output
var output = process.StandardOutput;
// Wait for the process to finish
process.WaitForExit();
this.currentProcess = null;
To kill the process I am using:
// Mark as not running to prevent starting new
this.isRunning = false;
// Kill the process
if (this.currentProcess != null)
{
this.currentProcess.Kill();
}
Thanks for reading!
EDIT
That the cli does not return seems to be not reproducible. When I test a different script (without arguments) it works, probably its the script or the passing of the arguments.
Running my script from cmd works just fine, so the script should not be the problem
EDIT 2
When disabling RedirectStandardOutput, the cli quits. could it be, that I need to read the output, before the process finishes? Or does the process wait, when some kind of buffer is full?
EDIT 3: Problem solved
Thanks to VolkerK, I / we found a solution. The problem was, that WaitForExit() did not get called, when the output is not read (probably due to a full buffer in the standard output). My script wrote much output.
What works for me:
process.Start();
// Get the output
var output = process.StandardOutput;
// Read the input and write to file, live to avoid reading / writing to much at once
using (var file = new StreamWriter("path\\file", false, new UTF8Encoding()))
{
// Read each line
while (!process.HasExited)
{
file.WriteLine(output.ReadLine());
}
// Read the rest
file.Write(output.ReadToEnd());
// flush to file
file.Flush();
}
Since the problem was that the output buffer was full and therefore the php process stalled while waiting to send its output, asynchronously reading the output in the c# program is the solution.
class Program {
protected static /* yeah, yeah, it's only an example */ StringBuilder output;
static void Main(string[] args)
{
// Create the process
var process = new System.Diagnostics.Process();
process.EnableRaisingEvents = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "php.exe";
process.StartInfo.Arguments = "-f path\\test.php mu b 0 0 pgsql://user:pass#x.x.x.x:5432/nominatim";
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.RedirectStandardOutput = true;
output = new StringBuilder();
process.OutputDataReceived += process_OutputDataReceived;
// Start the process
process.Start();
process.BeginOutputReadLine();
// Wait for the process to finish
process.WaitForExit();
Console.WriteLine("test");
// <-- do something with Program.output here -->
Console.ReadKey();
}
static void process_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data)) {
// edit: oops the new-line/carriage-return characters are not "in" e.Data.....
// this _might_ be a problem depending on the actual output.
output.Append(e.Data);
output.Append(Environment.NewLine);
}
}
}
see also: https://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline%28v=vs.110%29.aspx
This question already has answers here:
Process Exit Code When Process is Killed Forcibly
(2 answers)
Closed 7 years ago.
I have a method to install a program:
private void Install_Click(object sender, EventArgs e)
{
using (Process process = new Process())
{
// The installer itself
process.StartInfo.FileName = ExeFile;
if (fileArr1.Equals("installer.ini"))
process.StartInfo.Arguments = #"-if C:\temp\installer.ini";
if (fileArr1.Equals("installer_input.txt"))
process.StartInfo.Arguments = #"-if C:\temp\installer_input.txt";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
process.WaitForExit();
}
}
How I can make to appear a error message : " the process was stop " if the user stopping brutal the process?
If your process has a name, you could check this doing the folowing:
if (!Process.GetProcessesByName("process_name").Length > 0)
{
// Is not running
}
use BackgroundWorker and waitfrom, so user won't stop process
This question already has answers here:
C#: Redirect Standard Output of a Process that is Already Running
(4 answers)
Closed 8 years ago.
Can I get output of existing proccess? When I'm trying it says process is not running or doesn't have output redirect. Example I launched ping google.com -t (waited 20 seconds to have ouput) and I want last 10 lines from it:
var processes = Process.GetProcessesByName("PING").FirstOrDefault();
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
process.BeginOutputReadLine();
Any ideas how I can get it?
Try:
process.StartInfo.UseShellExecute = false;
process.Start();
process.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
process.BeginOutputReadLine();
I'm currently running the following code in order to test if an external application is actually consuming one of my dll's (updater code)
ProcessStartInfo psi = new ProcessStartInfo()
{
FileName = "Tasklist.exe",
Arguments = #"/m MyServices.dll",
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
};
Process p = new Process();
p.StartInfo = psi;
p.Start();
//debug output box, just to see everything that returns
txtOutput.Text = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Refresh();
if (txtOutput.Text.Contains("TestProgram.exe"))
MessageBox.Show("Found It");
Now, this code WORKS!!!....but its STUPID slow. I can type that same command into a cmd window and get a response in a tenth of a second, but for some reason the pause on that line p.StandardOutput.ReadToEnd() is taking anywhere from 1 to 5 MINUTES!!
And now the actual question:
Does anyone know why it would be that slow? Or possibly how to fix it and make it acceptably fast?
Update: More data
If I use a shell window and dont actually Capture the output, I can watch the task run in the shell window. It runs marginally (very marginally) faster, but still sits and takes a minute before the output starts appearing in the shell window. No idea what its doing.
StreamReader.ReadToEnd will block until all the data is read. Try using the Process.OutputDataReceived event.
Process p = new Process();
p.StartInfo = psi;
p.OutputDataReceived += OutputHandler;
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
p.OutputDataReceived -= OutputHandler;
private void OutputHandler(object sender, DataReceivedEventArgs outLine)
{
txtOutput.Text += outLine.Data;
}
I know this thread is really old, but I've just run into the same issue and just found a fix: use the x64 tasklist on x64 computers. Using the x86 .exe like you are here (in SysWow64) will result in a really long execution time - it doesn't hang, it just processes it really slowly. You should be using this file:
C:\Windows\sysnative\tasklist.exe