Executing BatchFile from C# program - c#

I am writing the batch file and executing it through C# program.
Writing Batch file :
I will get the Path, Executable name and arguments from app.config and write them to a batch file.
Executing Batch file :
Once I write the batch file I pass the file name to below function which executes the batch file to launches an application.
Problem :
My program will write a lot of batch files which are executed immediately after each and every file is written. I find that, some times the applications are not started which means that batch files are not executed. I didn't even get any error messages or prompts for this failure of batch file execution.
Expected solution :
Any problem in executing the batch file, I should be able to log it or prompt an error.
Code that executes Batch File :
System.Diagnostics.ProcessStartInfo procinfo = new System.Diagnostics.ProcessStartInfo("cmd.exe");
procinfo.UseShellExecute = false;
procinfo.RedirectStandardError = true;
procinfo.RedirectStandardInput = true;
procinfo.RedirectStandardOutput = true;
System.Diagnostics.Process process = System.Diagnostics.Process.Start(procinfo);
System.IO.StreamReader stream = System.IO.File.OpenText(BatchPath + LatestFileName);
System.IO.StreamReader sroutput = process.StandardOutput;
System.IO.StreamWriter srinput = process.StandardInput;
while (stream.Peek() != -1)
{
srinput.WriteLine(stream.ReadLine());
}
Log.Flow_writeToLogFile("Executed .Bat file : " + LatestFileName);
stream.Close();
process.Close();
srinput.Close();
sroutput.Close();

I'm not sure where your problem lies specifically but I've had no problems with the following code:
using (FileStream file = new FileStream("xyz.cmd", FileMode.Create)) {
using (StreamWriter sw = new StreamWriter(file)) {
sw.Write("#echo ====================\n");
sw.Close();
}
}
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "xyz.cmd";
//p.StartInfo.RedirectStandardOutput = true;
p.Start();
//String s = p.StandardOutput.ReadLine();
//while (s != null) {
// MessageBox.Show(s);
// s = p.StandardOutput.ReadLine();
//}
p.WaitForExit();
Obviously that's been cut down a bit for the purposes of hiding my "secret sauce" but that's code currently being used in production without issues.
I do have one question. Why don't you execute the cmd file directly rather than running cmd.exe?
Probably the first thing I'd do is to print out the BatchPath + LatestFileName value to see if you're creating any weirdly named files which would prevent cmd.exe from running them.

Related

Process exe stuck at specific files and how to move next file in the loop

I am trying to run a process in my code looping through each file and performing some task. Sometimes the EXE gets stuck when it runs across some files. And this doesn't move forward. If this kind of situation occurs how can I skip the files which is stuck in the process and save the file into a TXT file which has failed. And further move with the next file for processing. I tried to check it online and didn't get much help. Please suggest how can I get this done?
foreach (var file in files)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo
{
FileName = exedir + "\\testing.exe",
Arguments = "-a -h -i -l " + file,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (Process exeProcess = Process.Start(processStartInfo ))
{
var line = string.Empty;
using (StreamReader streamReader = exeProcess.StandardOutput)
{
while (!streamReader.EndOfStream)
{
var content = streamReader.ReadLine();
// Doing some task here
}
}
exeProcess.WaitForExit(10000);
}
}

Batch file stuck while unziping large files, when called from windows service..!

I have a windows service that calls a batch file. Batch file then calls commands to zip and unzip text files. Sometimes, while unzipping large files (approx. = 900MB) the process get stuck in between and then I have to stop windows service to release the process.Can anyone please suggest some solution to this problem?
I use following code to call batch file and retrieve return code from it:
objProcessStartInfo = new ProcessStartInfo(#out_Batch_File_Name);
objProcessStartInfo.UseShellExecute = false;
objProcessStartInfo.RedirectStandardOutput = true;
objProcessStartInfo.RedirectStandardError = true;
objProcessStartInfo.CreateNoWindow = true;
process = new Process();
process.Start Info = objProcessStartInfo;
process.Start();
process.WaitForExit();
returnCode = process.ExitCode;

Read GnuPlot output into image in C#

I am using GnuPlot from a C# application. I'd like to read the GnuPlot PNG output directly from Standard Output rather than saving to a file and then reading it. My code looks like this right now:
string Path = #"C:\Program Files\gnuplot\bin\gnuplot.exe";
Process GnuplotProcess = new Process();
GnuplotProcess.StartInfo.FileName = Path;
GnuplotProcess.StartInfo.UseShellExecute = false;
GnuplotProcess.StartInfo.RedirectStandardInput = true;
GnuplotProcess.StartInfo.RedirectStandardOutput = true;
GnuplotProcess.Start();
StreamWriter SW = GnuplotProcess.StandardInput;
StreamReader SR = GnuplotProcess.StandardOutput;
SW.WriteLine("set terminal pngcairo size 300,200");
foreach (LoadCaseOutput LCO in LoadCases)
{
foreach (LoadCaseOutput.MemberOutput MO in LCO.Members)
{
SW.WriteLine("plot " + MO.GenerateAFEquation(P));
MO.AFImage = Image.FromStream(SR.BaseStream);
}
}
SW.WriteLine("exit");
GnuplotProcess.Close();
Right now this seems to stall at the Image.FromStream() line. What's going wrong?
update (I have updated my code to reflect my comment below)
It appears the problem is when the "exit" command is sent to gnuPlot. Without the exit command sent to gnuPlot, the program waits.
I took your example and was able to get the program to complete by moving the gnuPlot exit command up in the execution tree.
string Path = #"z:\tools\gnuplot\bin\gnuplot.exe";
Process GnuplotProcess = new Process();
GnuplotProcess.StartInfo.FileName = Path;
GnuplotProcess.StartInfo.UseShellExecute = false;
GnuplotProcess.StartInfo.RedirectStandardInput = true;
GnuplotProcess.StartInfo.RedirectStandardOutput = true;
GnuplotProcess.Start();
StreamWriter SW = GnuplotProcess.StandardInput;
StreamReader SR = GnuplotProcess.StandardOutput;
SW.WriteLine("set terminal pngcairo size 300,200");
SW.WriteLine("plot f(x) = sin(x*a), a = .2, f(x), a = .4, f(x)");
SW.WriteLine("exit");
Image png = Image.FromStream(SR.BaseStream);
png.Save(#"z:\tools\try3a.png");
GnuplotProcess.Close();
This did correctly generate a PNG file. For testing, I did try reading from the stream before sending the exit command. The program waits on the FromStream call.
Matt
The problem is not with the reading otherwise you would be getting an exception, replace the reading bit with this:
Image.FromStream(oFileStream, false, true)
It will validate the image as soon as it receives the first bytes and you go from there.

How to read standard output of my own application

I have an application that must read it's own output that is written via
Console.WriteLine("blah blah");
I'm trying
Process p = Process.GetCurrentProcess();
StreamReader input = p.StandardOutput;
input.ReadLine();
But it doesn't work because of "InvalidOperationException" at the second line. It says something like "StandardOutput wasn't redirected, or the process has not been started yet" (translated)
How can I read my own output ? Is there another way to do that ? And to be complete how to write my own input ?
The application with the output is running already.
I want to read it's output live in the same application. There is no 2nd app. Only one.
I'm just guessing as to what your intention might be but if you want to read the output from a application you started you can redirect the output.
// 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();
example from http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx
Edit:
If you want to redirect the output of your current console application as your edit specifies you can use.
private static void Main(string[] args)
{
StringWriter writer = new StringWriter();
Console.SetOut(writer);
Console.WriteLine("hello world");
StringReader reader = new StringReader(writer.ToString());
string str = reader.ReadToEnd();
}

Reading System.Diagnostics.ProcessStartInfo StandardOutput as bytes instead of chars

I'm trying to automate svnadmin dump using C# ProcessStartInfo.
The way I've done it on the command line is like so,
svnadmin dump c:\Repositories\hackyhacky > c:\backup\hackyhacky.svn_dump
Works a treat and dumps successfully, and I can verify this by restoring it into another repository like so
svnadmin load c:\Repositories\restore_test < c:\backup\hackyhacky.svn_dump
Which restores successfully - yay!
Now... I need to replicate the command line piping into another file using C#, but for some reason
var startInfo = new ProcessStartInfo(Path.Combine(SvnPath, "svnadmin"),"dump c:\Repositories\hackyhacky")
{CreateNoWindow = true, RedirectStandardOutput = true,RedirectStandardError = true,UseShellExecute = false};
process.StartInfo = startInfo;
process.Start();
StreamReader reader = process.StandardOutput;
char[] standardOutputCharBuffer = new char[4096];
byte[] standardOutputByteBuffer;
int readChars = 0;
long totalReadBytes = 0;
// read from the StandardOutput, and write directly into another file
using (StreamWriter writer = new StreamWriter(#"C:\backup\hackyhacky.svn_dump", false)) {
while (!reader.EndOfStream) {
// read some chars from the standard out
readChars = reader.Read(standardOutputCharBuffer, 0, standardOutputCharBuffer.Length);
// convert the chars into bytes
standardOutputByteBuffer = reader.CurrentEncoding.GetBytes(standardOutputCharBuffer);
// write the bytes out into the file
writer.Write(standardOutputCharBuffer.Take(readChars).ToArray());
// increment the total read
totalReadBytes += standardOutputByteBuffer.Length;
}
}
Dumps the same repo into hackyhacky.svn_dump.
But when I run my load command line now
svnadmin load c:\Repositories\restore_test < c:\backup\hackyhacky.svn_dump
I get a checksum error weird-error!
svnadmin load c:\Repositories\restore_test < c:\backup\hackyhacky.svn_dump
< Started new transaction, based on original revision 1
* adding path : Dependencies ... done.
* adding path : Dependencies/BlogML.dll ...svnadmin: Checksum mismatch, fil
e '/Dependencies/BlogML.dll':
expected: d39863a4c14cf053d01f636002842bf9
actual: d19831be151d33650b3312a288aecadd
I'm guessing this is to do with how I'm redirecting and reading the StandardOutput.
Does anyone know the right way to mimic the command line file piping behaviour in C#?
Any help is greatly appreciated.
-CV
UPDATE
I've tried using a BinaryWriter and using the standardOutputByteBuffer to write to the file, but that doesn't work either. I get a different error about incorrect header format or something.
Alright! If you can't beat em, join em....
I found a post where the author pipes to a file directly within the Process StartInfo, and claims it works.
http://weblogs.asp.net/israelio/archive/2004/08/31/223447.aspx
It didn't work for me, as described in another gentleman's post
http://webcache.googleusercontent.com/search?q=cache:http://www.deadbeef.com/index.php/redirecting_the_output_of_a_program_to_a
He writes a batch file first with the piping and then executes it...
amWriter bat = File.CreateText("foo.bat");
bat.WriteLine("#echo off");
bat.WriteLine("foo.exe -arg >" + dumpDir + "\\foo_arg.txt");
bat.Close();
Process task = new Process();
task.StartInfo.UseShellExecute = false;
task.StartInfo.FileName = "foo.bat";
task.StartInfo.Arguments = "";
task.Start();
task.WaitForExit();
In his words:
Truly horrific, but it has the
advantage of working!
To be perfectly frank, I'm a bit annoyed this has taken me as long as it has, so the batch file solution works well so I'm going to stick with it.
The first thing I'd try is writing the character array - not the byte array - to the file.
That should work as long as the output is just simple text. There's other encoding issues, though, if the output is more complex: you're writing the file as UTF-8, whereas the default for command-line output (I believe) is Windows-1252.
I've been trying to do this very thing, and just stumbled on another solution to the problem used by Hector Sosa's svnmanagerlib sourceforge project:
The key to solving this was surrounding the call to WaitForExit() with
file operations. Also needed to make sure to write the output to disk.
Here are the relevant lines:
File.AppendAllText( destinationFile, myOutput.ReadToEnd() );
svnCommand.WaitForExit(); File.AppendAllText(destinationFile,
myOutput.ReadToEnd() );
Notice that I make a call to File.AppendAllText() twice. I have found
that the output stream does not write everything during the first call
to File.AppendAllText() on some occasions.
public static bool ExecuteWritesToDiskSvnCommand(string command, string arguments, string destinationFile, out string errors)
{
bool retval = false;
string errorLines = string.Empty;
Process svnCommand = null;
ProcessStartInfo psi = new ProcessStartInfo(command);
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
try
{
Process.Start(psi);
psi.Arguments = arguments;
svnCommand = Process.Start(psi);
StreamReader myOutput = svnCommand.StandardOutput;
StreamReader myErrors = svnCommand.StandardError;
File.AppendAllText(destinationFile, myOutput.ReadToEnd());
svnCommand.WaitForExit();
File.AppendAllText(destinationFile, myOutput.ReadToEnd());
if (svnCommand.HasExited)
{
errorLines = myErrors.ReadToEnd();
}
// Check for errors
if (errorLines.Trim().Length == 0)
{
retval = true;
}
}
catch (Exception ex)
{
string msg = ex.Message;
errorLines += Environment.NewLine + msg;
}
finally
{
if (svnCommand != null)
{
svnCommand.Close();
}
}
errors = errorLines;
return retval;
}

Categories

Resources