I have an exe which has some parameters- path of another application and some files to be opened from that application. There would be an output as part of that application which would be displayed in the console of my exe.
But i am unable to get the output from the console.
I have the code:
ProcessStartInfo psi = new ProcessStartInfo("\"" + dllpath + "\\newapplication.exe" + "\"");
Process p = new Process();
psi.UseShellExecute = false;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
p.Start();
The process starts successfully, and then i have to open a file in the process which happens through another class. So after the file opened, some extraction happens and the result is displayed on the console.
When i give p.WaitForExit(); nothing happens other than starting the application! How do i acheive to retreive the output on StandardOutput as per my code? Need Help!
This is the correct way to do it:
string outputProcess = "";
string errorProcess = "";
using (Process process = new Process())
{
process.StartInfo.FileName = path;
process.StartInfo.Arguments = arguments;
process.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
outputProcess = process.StandardOutput.ReadToEnd();
errorProcess = process.StandardError.ReadToEnd();
process.WaitForExit();
}
Remember to use the using statement when you have an IDisposable object
This question already has answers here:
Capturing console output from a .NET application (C#)
(8 answers)
Closed 6 years ago.
I need to spawn a child process that is a console application, and capture its output.
I wrote up the following code for a method:
string retMessage = String.Empty;
ProcessStartInfo startInfo = new ProcessStartInfo();
Process p = new Process();
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = command;
startInfo.FileName = exec;
p.StartInfo = startInfo;
p.Start();
p.OutputDataReceived += new DataReceivedEventHandler
(
delegate(object sender, DataReceivedEventArgs e)
{
using (StreamReader output = p.StandardOutput)
{
retMessage = output.ReadToEnd();
}
}
);
p.WaitForExit();
return retMessage;
However, this does not return anything. I don't believe the OutputDataReceived event is being called back, or the WaitForExit() command may be blocking the thread so it will never callback.
Any advice?
EDIT: Looks like I was trying too hard with the callback. Doing:
return p.StandardOutput.ReadToEnd();
Appears to work fine.
Here's code that I've verified to work. I use it for spawning MSBuild and listening to its output:
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, args) => Console.WriteLine("received output: {0}", args.Data);
process.Start();
process.BeginOutputReadLine();
I just tried this very thing and the following worked for me:
StringBuilder outputBuilder;
ProcessStartInfo processStartInfo;
Process process;
outputBuilder = new StringBuilder();
processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardInput = true;
processStartInfo.UseShellExecute = false;
processStartInfo.Arguments = "<insert command line arguments here>";
processStartInfo.FileName = "<insert tool path here>";
process = new Process();
process.StartInfo = processStartInfo;
// enable raising events because Process does not raise events by default
process.EnableRaisingEvents = true;
// attach the event handler for OutputDataReceived before starting the process
process.OutputDataReceived += new DataReceivedEventHandler
(
delegate(object sender, DataReceivedEventArgs e)
{
// append the new data to the data already read-in
outputBuilder.Append(e.Data);
}
);
// start the process
// then begin asynchronously reading the output
// then wait for the process to exit
// then cancel asynchronously reading the output
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
process.CancelOutputRead();
// use the output
string output = outputBuilder.ToString();
Here's some full and simple code to do this. This worked fine when I used it.
var processStartInfo = new ProcessStartInfo
{
FileName = #"C:\SomeProgram",
Arguments = "Arguments",
RedirectStandardOutput = true,
UseShellExecute = false
};
var process = Process.Start(processStartInfo);
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
Note that this only captures standard output; it doesn't capture standard error. If you want both, use this technique for each stream.
I needed to capture both stdout and stderr and have it timeout if the process didn't exit when expected. I came up with this:
Process process = new Process();
StringBuilder outputStringBuilder = new StringBuilder();
try
{
process.StartInfo.FileName = exeFileName;
process.StartInfo.WorkingDirectory = args.ExeDirectory;
process.StartInfo.Arguments = args;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = false;
process.OutputDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data);
process.ErrorDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
var processExited = process.WaitForExit(PROCESS_TIMEOUT);
if (processExited == false) // we timed out...
{
process.Kill();
throw new Exception("ERROR: Process took too long to finish");
}
else if (process.ExitCode != 0)
{
var output = outputStringBuilder.ToString();
var prefixMessage = "";
throw new Exception("Process exited with non-zero exit code of: " + process.ExitCode + Environment.NewLine +
"Output from process: " + outputStringBuilder.ToString());
}
}
finally
{
process.Close();
}
I am piping the stdout and stderr into the same string, but you could keep it separate if needed. It uses events, so it should handle them as they come (I believe). I have run this successfully, and will be volume testing it soon.
It looks like two of your lines are out of order. You start the process before setting up an event handler to capture the output. It's possible the process is just finishing before the event handler is added.
Switch the lines like so.
p.OutputDataReceived += ...
p.Start();
Redirecting the stream is asynchronous and will potentially continue after the process has terminated. It is mentioned by Umar to cancel after process termination process.CancelOutputRead(). However that has data loss potential.
This is working reliably for me:
process.WaitForExit(...);
...
while (process.StandardOutput.EndOfStream == false)
{
Thread.Sleep(100);
}
I didn't try this approach but I like the suggestion from Sly:
if (process.WaitForExit(timeout))
{
process.WaitForExit();
}
You need to call p.Start() to actually run the process after you set the StartInfo. As it is, your function is probably hanging on the WaitForExit() call because the process was never actually started.
The answer from Judah did not work for me (or is not complete) as the application was exiting after the first BeginOutputReadLine();
This works for me as a complete snippet, reading the constant output of a ping:
var process = new Process();
process.StartInfo.FileName = "ping";
process.StartInfo.Arguments = "google.com -t";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.OutputDataReceived += (sender, a) => Console.WriteLine(a.Data);
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
Here's a method that I use to run a process and gets its output and errors :
public static string ShellExecute(this string path, string command, TextWriter writer, params string[] arguments)
{
using (var process = Process.Start(new ProcessStartInfo { WorkingDirectory = path, FileName = command, Arguments = string.Join(" ", arguments), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true }))
{
using (process.StandardOutput)
{
writer.WriteLine(process.StandardOutput.ReadToEnd());
}
using (process.StandardError)
{
writer.WriteLine(process.StandardError.ReadToEnd());
}
}
return path;
}
For example :
#"E:\Temp\MyWorkingDirectory".ShellExecute(#"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\svcutil.exe", Console.Out);
Thanks to #user2526830 for the code. Based on that code I added few lines to my program since I want to read the output of the SSH command. Below is my code which gives an error at line while
StandardOut has not been redirected or the process hasn't started yet.
What I want to achieve is that I want to read the output of ls into a string.
ProcessStartInfo startinfo = new ProcessStartInfo();
startinfo.FileName = #"f:\plink.exe";
startinfo.Arguments = "-ssh abc#x.x.x.x -pw abc123";
Process process = new Process();
process.StartInfo = startinfo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.StandardInput.WriteLine("ls -ltr /opt/*.tmp");
process.StandardInput.WriteLine("exit");
process.StartInfo.RedirectStandardOutput = true;
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
}
process.WaitForExit();
Console.ReadKey();
Try setting standard output redirection before starting the process.
process.StartInfo.RedirectStandardOutput = true;
process.Start();
It might be that the process already terminated when you try to read the output (dues to your "exit" command). Try the below slightly modified version where I moved your while loop after the "ls" command but before the "exit" command.
It should read the output of your "ls" command fine, but unfortunately will most probably hang at some point as you will never get EndOfStream on the StandardOutput. When there is nothing more to read, ReadLine will block until it can get read another line.
So unless you know how to detect the last line of the output generated by your command and break out of the loop after you read it, you may need to use a separate thread either for reading or for writing.
ProcessStartInfo startinfo = new ProcessStartInfo();
startinfo.FileName = #"f:\plink.exe";
startinfo.Arguments = "-ssh abc#x.x.x.x -pw abc123";
Process process = new Process();
process.StartInfo = startinfo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.StandardInput.WriteLine("ls -ltr /opt/*.tmp");
while (!process.StandardOutput.EndOfStream)
{
string line = process.StandardOutput.ReadLine();
}
process.StandardInput.WriteLine("exit");
process.WaitForExit();
Console.ReadKey();
This question already has answers here:
How to uninstall with msiexec using product id guid without .msi file present
(7 answers)
Closed 6 years ago.
There are lots of program so if i know its guid value how can i uninstall using msiexec.exe from c#
public void msi(string path)
{
//get msiexec.exe /X{GUID} from path
int slash = path.IndexOf(#"/");
//get the substring as /I{GUID}
String value = path.Substring(slash, (path.Length) - slash);
MessageBox.Show(value);
Process process = new Process();
process.StartInfo.FileName = #"msiexec.exe";
process.StartInfo.Arguments = string.Format(value);//Error is in this line
//`i just want to know how to pass the agrument to msiexec from c#`
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = false;
process.Start();
process.WaitForExit();
}
Thanks everyone for the support this code works for me
Process p = new Process();
p.StartInfo.FileName = "msiexec.exe";
//The argument that you want to give
p.StartInfo.Arguments = "/X{0784DF00-13E1-40D1-8BC4-E081AD2DA509}";
p.Start();
I am trying to start a process on Mac and Windows (using Unity) to run FFMPEG to convert a video to a .ogv video. My code is as follows:
string command = "ffmpeg -i '" + filepath + "' -codec:v libtheora -qscale:v 10 -codec:a libvorbis -qscale:a 10 -y '"+workingDir+"/ogv_Video/"+System.IO.Path.GetFileNameWithoutExtension(filepath)+".ogv'";
UnityEngine.Debug.Log("Command: "+command);
try{
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo (workingDir+"/..", command);
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.FileName =workingDir+"/ffmpeg";
//Process.Start (startInfo);
Process p = Process.Start(startInfo);
p.EnableRaisingEvents = true;
string strOutput = p.StandardOutput.ReadToEnd();
UnityEngine.Debug.Log ("Running..."+strOutput);
p.WaitForExit();
UnityEngine.Debug.Log ("Got here. "+strOutput);
int exitCode = p.ExitCode;
UnityEngine.Debug.Log ("Process exit code = "+exitCode);
}
catch(Exception e) {
UnityEngine.Debug.Log ("An error occurred");
UnityEngine.Debug.Log ("Error: "+e);
}
The command executes and does not through any exception. However, it terminates instantly and prints Exit Code 1 which is "Catchall for general errors" -this seems not too helpful!
What am I doing wrong with my code, please?
You'll notice that my code prints out the command in full. If I copy that command and paste it into the terminal, it runs absolutely fine.
It turns out I was setting up the arguments wrongly. Referring to this Stack Overflow question, I was able to produce the expected result with the following code:
try{
Process process = new Process();
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) +#"ffmpeg";
process.StartInfo.Arguments = command;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
JSONDataObject rtnMsg = new JSONDataObject("StartConvertOK", "-1", new List<string>());
return JsonUtility.ToJson(rtnMsg);
}
It does seem as though the answer was not that different from what I was doing, but it does work!