am doing application of downloading images using wget process in c#.
But while downloading images I am providing type of image i.e. .jpeg or .png. Through wget command.
If while downloading I am passing .jpeg and if .jpeg is not present, Then I want to trap error "file not found" through process class. But it is not happening.
My code is below:
class TrapProcessError
{
private Process process = new Process();
public TrapProcessError()
{
}
public void Start()
{
string args= "-r -c -np --retry-connrefused --tries=0 "url containing image folder" -P C:\\Images --cut-dirs=2 -nH -A jpeg -o C:\\Images\\error.log";
string filename= "path of wget\\wget.exe";
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = args;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.ErrorDataReceived += this.ProcessErrorData;
process.OutputDataReceived += this.ProcessOutputData;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
}
private void ProcessErrorData(object sender, DataReceivedEventArgs e)
{
string message = e.Data;
if (message.Contains("file not found"))
{
Console.WriteLine("Error :" +message);
process.Close();
}
}
private void ProcessOutputData(object sender, DataReceivedEventArgs e)
{
string message = e.Data;
Console.WriteLine("Output :" +message);
}
public static void Main(string[] args)
{
TrapProcessError trapProcessError= new TrapProcessError();
trapProcessError.Start();
}
}
In above code if jpeg is not present then in erroe.log coming "file not found". But through process class not trapping error i.e. in ProcessErrorData e.Data is always coming null. So how can I trap error is there any other way?
Any Help is appreciated.
wget (in versions above 1.12) does return a reliable exitcode.
0 No problems occurred.
1 Generic error code.
2 Parse error—for instance, when parsing command-line options, the ‘.wgetrc’ or ‘.netrc’...
3 File I/O error.
4 Network failure.
5 SSL verification failure.
6 Username/password authentication failure.
7 Protocol errors.
8 Server issued an error response.
Prior to 1.12 you're in trouble:
In versions of Wget prior to 1.12, Wget’s exit status tended to be unhelpful and inconsistent. Recursive downloads would virtually always return 0 (success), regardless of any issues encountered, and non-recursive fetches only returned the status corresponding to the most recently-attempted download.
The exitcode of the process is handed back to the Process instance in the ExitCode property. You should leverage that and keep the (error) logging for convenience.
public void Start()
{
string args= "-r -c -np --retry-connrefused --tries=0 "url containing image folder" -P C:\\Images --cut-dirs=2 -nH -A jpeg -o C:\\Images\\error.log";
string filename= "path of wget\\wget.exe";
process.StartInfo.FileName = filename;
process.StartInfo.Arguments = args;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.ErrorDataReceived += this.ProcessErrorData;
process.OutputDataReceived += this.ProcessOutputData;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
if (process.ExitCode > 0)
{
// do what you need to do in case of an Error
Console.WriteLine("Error occured:{0}", process.ExitCode);
}
}
If you absolutely want to respond to the error messages that are logged (either to standardoutout or erroroutput), make sure you check the correct strings: If the log shows ERROR 404: Not Found then this message.Contains("file not found") will never be true. This is a reason I always tend to stay away from logfile parsing.
Do notice that processes are not required to write errormessage to the standard error stream. The errormessages can very well come in the standard output stream as well...
Related
I have been trying to transfer the files using the tftp in C#.
I implemented it with the Process class.
I have turn on the TFTP client feature in Windows.
This is the command -
C:\Users\Desktop>tftp -i 192.168.43.171 put
"C:\Users\cc\callisto\SampleTool\src\SampleTool\bin\Debug\DecryptedFiles\dserc.bin"
Transfer successful: 32 bytes in 1 second(s), 32 bytes/s
And the transfer is successful when I execute it manually
But When I try it through the code, it says its not recognized -
'tftp' is not recognized as an internal or external command,
operable program or batch file.
Here is my code
public static void ExecuteCommand(string fileName, string command)
{
try
{
Process process = new Process();
process.StartInfo.FileName = fileName;//cmd.exe
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
process.StandardInput.WriteLine(command);//tftp command
process.StandardInput.Flush();
process.StandardInput.Close();
process.WaitForExit();
}
catch (Exception ex)
{ }
}
What is the exact issue I am facing. Can anyone help
Thanks.
So after so much complication I found this link [https://github.com/Callisto82/tftp.net/blob/master/Tftp.Net.SampleClient/Program.cs]
I was able to transfer the file successfully without any issue.
Hopefully this helps
I want to receive information from a device connected in USB via a C# program using ADB commands then flush the output.
Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "logcat -d -b main -v raw -s Command:I"; // get data in Log.I() with name == "Command"
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
string output;
do {
process.StandardInput.WriteLine("logcat -d -b main -v raw -s Command:I");
output = process.StandardOutput.ReadToEnd();
} while (output.Length < 1);
Console.WriteLine(output);
process.StandardInput.WriteLine("logcat -c"); // flush logcat
process.WaitForExit();
Doing that I understand that the program is constantly executing adb logcat -d -b main -v raw -s Command:I, isn't there a way to call a command one time and wait for the output?
I can do that in windows prompt using :
adb shell 'logcat -b main -v raw -s UNIQUE_TAG:I | (read -n 1 && kill -2 $((BASHPID-1)))'
but is this doable in C#?
Also the output doesn't seem to be flushed
You can't read to the end more than once; ReadToEnd ultimately means "until the pipe is closed and I've consumed everything, and no more data will ever ever arrive". ReadToEnd will also never finish until adb.exe either intentionally signals that it is done writing (and will never write again), or terminates - so this is why you aren't getting as far as flushing.
What you can do is read (a byte/character at a time, if needed) until you have, say, a single line - so if the expectation here is "one command in, one line out" then it is simple enough. If there isn't a way of knowing how many lines will come back, then you would usually use two threads, and have a dedicated reader thread that takes data from the process.StandardOutput (byte/character at a time, or line by line) and does whatever is needed with it.
This is how i used to code for such things
Here is my code Hope u understand it
//to run the all the cmd,adb.fastboot.exe command using these function
//here in startfunc pass the .exe file u want to execute,Arguments which u want to pass
//string msg = It is nothing Extra message if u want to add to your final output
private static string Execute(string Startfunc, String Arguments,string msg)
{
string text = null;
Process p = new Process();
p.StartInfo.FileName = Startfunc;
p.StartInfo.Arguments = Arguments;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.EnableRaisingEvents = true;
p.Start();
do
{
Application.DoEvents();
string output = p.StandardOutput.ReadToEnd();
text += output;
string err = p.StandardError.ReadToEnd();
text += err;
}
while (!p.HasExited);
text += msg;
return text;
}
//now i will call above function and make it wait until we get the result
private void normal_reboot_Click(object sender, EventArgs e)
{
txt_Log.Text = "rebooting" +Environment.NewLine;
Task t = Task.Factory.StartNew(() =>
{
txt_Log.Text=Execute("adb.exe","reboot","Done");
});
do { Application.DoEvents(); } while (!t.IsCompleted);
}
You can also look for output/error messages asyncly. So you don't need a (blocking) loop:
This example just outputs the messages, but can be extended by full methods
p.OutputDataReceived+= (s, e) => Console.WriteLine(e.Data);
p.BeginOutputReadLine();//This is important, otherwise the event won't be fired
p.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
p.BeginErrorReadLine();
This should print every line received by adb
Working code below, we don't call adb.exe directly but through cmd.exe with a command waiting for any information log coming from logcat with the title "Command" : adb shell logcat -b main -v raw -s Command:I
private Process listeningProc;
public someClass(){
listeningProc = new Process();
listeningProc.StartInfo.FileName = "cmd.exe";
listeningProc.StartInfo.UseShellExecute = false;
listeningProc.StartInfo.RedirectStandardOutput = true;
listeningProc.StartInfo.RedirectStandardInput = true;
listeningProc.Start();
listeningProc.OutputDataReceived += new DataReceivedEventHandler(
(s, e) => {
if (e.Data == "SPECIFIC_COMMAND") {
// do something
}
}
);
listeningProc.BeginOutputReadLine();
}
private void ListenToCommands(){
listeningProc.StandardInput.WriteLine("adb shell logcat -b main -v raw -s Command:I"); //Listening for Info Logs titled "Command"
while (true) { }
}
To flush logcat or send any command from the PC through ADB, I open another process and send the commands from there.
Edit:
You might want to add System.Threading.Thread.Sleep(2000); //pause for 2 seconds after each commands sent from the PC through ADB otherwise the device sometimes doesn't execute all commands when sent successively too quickly
I`m working in the CLI commands in my Visual Studio C# application. This application does the interface with the Flash Programmer 2 (Texas Instruments Software to bootload the firmware in CC2560) using CLI ( Command-Line interface).
I checked some examples in StackOverflow, but I didn't have success to implement the solutions.
Steps of my application:
Select the serial port
Open the console
execute the srfprog.exe
execute the command line (srfprog -t soc(COM84,CC2650) -e -p -v -f c:\test.bin )
Check if the programming was a success
My file is located in: D:\Projects\Test_Fixture\Test_Fixture_Visual_Studio\SmartRF Tools\Flash Programmer 2\bin\srfprog.exe
When I execute this in my CMD (windows) the Prompt window shows
After this screen pop up I sent the commands to program the chip
srfprog -t soc(COM84,CC2650) -e -p -v -f c:\test.bin
This command will program and verify the code in the microcontroller CC2650 as show in the screenshot below:
The programming is perfect.
However when I run(Click the button - Load Firmware) my application open and close Shell window immediately. As shown in the figure below
My code is below:
private void button2_Click(object sender, EventArgs e)
{
System.Diagnostics.Process CC2650 = new System.Diagnostics.Process();
CC2650.StartInfo.FileName = #"D:\Projects\Test_Fixture\Test_Fixture_Visual_Studio\SmartRF Tools\Flash Programmer 2\bin\srfprog.exe";
CC2650.StartInfo.Arguments = "srfprog -t soc(COM84,CC2650) -e -p -v -f c:\test.bin"; //argument
CC2650.StartInfo.UseShellExecute = false;
CC2650.StartInfo.RedirectStandardOutput = true;
CC2650.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
CC2650.StartInfo.CreateNoWindow = false; //not diplay a windows
CC2650.Start();
string output = CC2650.StandardOutput.ReadToEnd(); //The output result
CC2650.WaitForExit();
}
In this test I`m using the fixed COM port. Later I will select the port.
Why my software is falling and doesn`t load the firmware?
Thank you for your attention and time.
Your code seems to be doubling up on srfprog by including it in the arguments. Filename defines the executable and Arguments should just be the stuff that comes after the Filename.
CC2650.StartInfo.Arguments = "-t soc(COM84,CC2650) -e -p -v -f c:\test.bin";
As mentioned before you don't need to pass the program name again in the arguments. To inspect what is happening please use code below. It will read the output and the errors in an async approach so we can analyse the output while the srfprog.exe is running.
I don't have any C# compiler here so I could not test this code before writing here, maybe you will have to change something to make it work. Please try it and let my know what will be printed in your Visual Studio output console.
// Add "using System.Diagnostics;"
private void button2_Click(object sender, EventArgs e)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"D:\Projects\Test_Fixture\Test_Fixture_Visual_Studio\SmartRF Tools\Flash Programmer 2\bin\srfprog.exe";
startInfo.Arguments = "-t soc(COM84,CC2650) -e -p -v -f c:\test.bin";
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
Process process = new Process();
process.StartInfo = startInfo;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine(outLine.Data);
}
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:
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.