I want to send commands with arguments and read their answers from cmd. So, I wrote the code below, but it is not working and locks on screen (myString is usually null - ""). I only want to send commands to an opened command prompt. Where is the problem? Thanks in advance. (for example: How can I fetch the result of a ping request?)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
namespace CallBatchFile
{
class Program
{
[STAThread]
static void Main()
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c date";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string myString = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
}
}
cmd /c date is blocking. you can either use
p.StartInfo.Arguments = "/c date /T";
To stop date waiting for input, or give input to cmd
p.StartInfo.RedirectStandardInput = true;
...
p.StandardInput.Write("\n");
..or read async so you can get the output while cmd is waiting for your input:
p.BeginOutputReadLine();
p.OutputDataReceived += (_, e) => Console.WriteLine(e.Data);
This code might help you
string strOutput;
//Starting Information for process like its path, use system shell i.e. control process by system etc.
ProcessStartInfo psi = new ProcessStartInfo(#"C:\WINDOWS\system32\cmd.exe");
// its states that system shell will not be used to control the process instead program will handle the process
psi.UseShellExecute = false;
psi.ErrorDialog = false;
// Do not show command prompt window separately
psi.CreateNoWindow = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
//redirect all standard inout to program
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
//create the process with above infor and start it
Process plinkProcess = new Process();
plinkProcess.StartInfo = psi;
plinkProcess.Start();
//link the streams to standard inout of process
StreamWriter inputWriter = plinkProcess.StandardInput;
StreamReader outputReader = plinkProcess.StandardOutput;
StreamReader errorReader = plinkProcess.StandardError;
//send command to cmd prompt and wait for command to execute with thread sleep
inputWriter.WriteLine("C:\\PLINK -ssh root#susehost -pw opensuselinux echo $SHELL\r\n");
Thread.Sleep(2000);
// flush the input stream before sending exit command to end process for any unwanted characters
inputWriter.Flush();
inputWriter.WriteLine("exit\r\n");
// read till end the stream into string
strOutput = outputReader.ReadToEnd();
//remove the part of string which is not needed
int val = strOutput.IndexOf("-type\r\n");
strOutput = strOutput.Substring(val + 7);
val = strOutput.IndexOf("\r\n");
strOutput = strOutput.Substring(0, val);
MessageBox.Show(strOutput);
Related
I want to automate the flashing of hardware using the command prompt. I have checked to see if the strings passed to the command prompt from atprogram.exe are correct and now have narrowed it down to my output
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace AutoFlash
{
class Program
{
public static void Main(string[] args)
{
string atProgramLocaction = "\"C:\\Program Files
(x86)\\Atmel\\Studio\\7.0\\atbackend\\atprogram.exe\"";
string atProgramArgs = "-t atmelice -i swd -d DEVICENAME program
-f";
string fileLocation = "C\:\FILE.HEX";
string command = atProgramLocaction + " " + atProgramArgs + " " +
fileLocation;
Process AtmelCommand = new Process();
AtmelCommand.StartInfo.FileName = "cmd.exe";
AtmelCommand.StartInfo.Arguments = command;
AtmelCommand.StartInfo.RedirectStandardInput = true;
AtmelCommand.StartInfo.UseShellExecute = false;
AtmelCommand.StartInfo.RedirectStandardOutput = true;
AtmelCommand.Start();
Console.WriteLine(AtmelCommand.StandardOutput.ReadToEnd());
AtmelCommand.WaitForExit();
}
}
}
Ideally would like to see the atmel command line output "Firmware check OK
Programming completed successfully" passed to cmd.exe and printed to confirm to user that firmware flashed successfully. What is currently happening is a blank command line window popping up.Any help with this would be appreciated!
A few things; the output may be coming on StandardError instead of StandardOut, also, I think you need to read the streams after the WaitForExit.
Try something like this:-
var psi = new ProcessStartInfo();
psi.FileName = "program.exe";
psi.Arguments = "-v";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var p = Process.Start(psi);
var stdout = string.Empty;
var stderr = string.Empty;
p.ErrorDataReceived += (sender, e) =>
{
stderr += e.Data;
};
p.BeginErrorReadLine();
string line;
while ((line = p.StandardOutput.ReadLine()) != null)
{
stdout += line;
}
p.WaitForExit();
Console.WriteLine(stdout);
Console.WriteLine(stderr);
Console.WriteLine(p.ExitCode);
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);
I'm writing a program that reads python script output and shows the results in textbox.
Since the script runnning for a long time, I want to be able to see the output every 1 second (or after each line is writen).
Now i can see the output only when the process ends.
Does someone know what is the problem?
snippet of my code:
Process p = new Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.OutputDataReceived += new DataReceivedEventHandler (p_OutputDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler (p_ErrorDataReceived);
p.Exited += new EventHandler (p_Exited);
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "python.exe";
p.StartInfo.Arguments = "path " + commandline;
p.Start();
StreamReader s = p.StandardOutput;
String output = s.ReadToEnd();
textBox3.Text = output;
p.WaitForExit();
I'm doing it the following way in my own programs:
private static void startProgram(
string commandLine )
{
var fileName = commandLine;
var arguments = string.Empty;
checkSplitFileName( ref fileName, ref arguments );
var info = new ProcessStartInfo();
info.FileName = fileName;
info.Arguments = arguments;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
using ( var p = new Process() )
{
p.StartInfo = info;
p.EnableRaisingEvents = true;
p.OutputDataReceived += (s,o) => {
Console.WriteLine(o.Data);
};
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
}
}
I.e. I'm subscribing to the OutputDataReceived event and calling BeginOutputReadLine method. See also this similar Stack Overflow question.
(The method checkSplitFileName in my above source code can be found here)
I had this same problem running my Python script from C#. The problem is that Python buffers the output from stdout (print()).
You could do one of two things here.
1.
Add the following to your Python script, after every print() line to flush the output.
import sys
print('Hello World!')
sys.stdout.flush()
2.
Run the Python compiler with the -u command line parameter. This way you don't need to add the above flush line after every print.
...
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "python.exe -u path " + commandline;
...
Python, by default, buffers its output.
The way to go is to pass a "-u" command line argument to python.
so if you want to execute say hello.py, you would do :
python.exe -u hello.py
Heres the C# code that works for me.
Process p = new Process();
string op = "";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = "c:\\python27\\python.exe";
StreamReader outputStream = p.StandardOutput;
StreamReader errorStream = p.StandardError;
p.StartInfo.Arguments = #"-u hello.py";
p.Start();
string output = "";
int offset = 0, readBytes = 0;
char[] buffer = new char[512];
do
{
output = outputStream.ReadLine();
if (!string.IsNullOrEmpty(output))
{
txtOutput.AppendText(output);
txtOutput.AppendText(Environment.NewLine);
offset += readBytes;
Application.DoEvents();
}
Thread.Sleep(3);
} while (!p.HasExited);
I'm looking to trigger the child command window's close event once its command is finished. Keep in mind, it's a background process initiated from a console app so it's never visible. What is visible is the console application.
I tried using the Exited event, but that didn't work. I tried relying on CMD to know when to close it by using /c, /k, and exit. Neither seem to work. I also tried a do while loop checking HasExited, none of these have worked unless I type "exit" within the application console window. It does not close, but somehow triggers the invisible child command windows to close.
Is there another way of closing it once the child command is complete?
String msg = "echo %time%; exit;";
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = msg;
p.EnableRaisingEvents = true;
p.Exited += p_Exited;
p.Start();
msg += p.StandardOutput.ReadToEnd();
Thank you very much!!
I modified your program slightly to run a child command processor, capture its output, then write it to console.
char quote = '"';
string msg = "/C " + quote + "echo %time%" + quote;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = msg;
p.EnableRaisingEvents = true;
p.Exited += (_, __) => Console.WriteLine("Exited!");
p.Start();
string msg1 = p.StandardOutput.ReadToEnd();
Console.WriteLine(msg1);
Here's a full program, using slightly different syntax, but similar in spirit:
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
char quote = '"';
var startInfo = new ProcessStartInfo("cmd", "/C " + quote + "echo %time%" + quote)
{ UseShellExecute = false, RedirectStandardOutput = true };
var process = new Process { EnableRaisingEvents = true };
process.StartInfo = startInfo;
process.Exited += (_, __) => Console.WriteLine("Exited!");
process.Start();
string msg1 = process.StandardOutput.ReadToEnd();
Console.WriteLine(msg1);
Console.ReadLine();
}
}
}
Or, as this answer illustrates, maybe just call DateTimeOffset.Now. If you're interested in looking at sub-second info, maybe use Stopwatch class instead.
If you prefer to drive command line with commands from C#, it's also possible. Igor Ostrovsky describes how to convert events to Tasks; then use async/await to create a procedural-looking sequence of commands and responses.
I want to launch a .exe program using C# and read the values from the cmd generated from the .exe
The .exe launches successfully but I cannot read the values:
This is my code:
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = (#"D:\BSC\Thesis\Raphael_Thesis\smiledetector\bin\smiledetector.exe");
start.WorkingDirectory = #"D:\BSC\Thesis\Raphael_Thesis\smiledetector\bin\";
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
//Start the process
using (Process process = Process.Start(start))
{
// Read in all the text from the process with the StreamReader.
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
textBox1.Text = result;
}
}
As Sam I Am has indicated, drop the using block for the StreamReader
using (Process process = Process.Start(start))
{
string result = process.StandardOutput.ReadToEnd();
textBox1.Text = result;
}
Keep in mind however your calling application will block until process completes and all the output can be read.
You need something like this:
private void btnStart_Click(object sender, EventArgs e)
{
p.StartInfo.FileName = #"D:\BSC\Thesis\Raphael_Thesis\smileDetector\vs2010\smiledetectorDebug";
p.StartInfo.WorkingDirectory = #"D:\BSC\Thesis\Raphael_Thesis\smileDetector\vs2010\";
p.StartInfo.RedirectStandardOutput = true;
p.EnableRaisingEvents = true;
p.StartInfo.UseShellExecute = false;
p.OutputDataReceived += new DataReceivedEventHandler(OutputHander);
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
}
where p is Process p = new Process();
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
data.Add(Convert.ToInt32(e.Data));
}
where data is a List of int
I don't see any weird thing in your code, it should work fine. Taking a look at the doc, it gives a brief example of how to redirect it:
// Start the child process.
using(Process p = new Process())
{
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = #"D:\BSC\Thesis\Raphael_Thesis\smiledetector\bin\smiledetector.exe";
p.WorkingDirectory = #"D:\BSC\Thesis\Raphael_Thesis\smiledetector\bin\";
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();
}
source: Process.StandardOutput Property