why WaitForExit() doesn't wait? - c#

i am adding Custom Action into my VS2008 setup project (MSI installer).
I am calling a batch file to create database and want to delete those files after. I have WaitForExit() but it will not wait. Why?
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = false;
string tempDir = #"C:\Temp\";
startInfo.FileName = tempDir + "sybaseDB\\en_AllInOne_installDB.bat";
startInfo.Arguments = tempDir + "sybaseDB\\";
try
{
Process startDB = Process.Start(startInfo);
startDB.WaitForExit();
}
catch (Exception e)
{
//do something?
}
finally {
System.IO.File.Delete(tempDir);
}
no difference with startInfo.UseShellExecute = true;
The batch was executed without any problem because it require user input and I input y and n for questions. but that delete action happened before my input. And I have a pause at the end of the batch file. I can watch the process of the batch file going.
EDIT:
I tested more than 10 times, it didn't work. After lunch, I put one more waitForExit and a while loop with HasExited check. it will sleep inside the while loop. I found it worked. Then I deleted those extra code, back to one WaitForExit. It seems work now.

This is probably throwing an exception because you can't execute a .bat file. You probably intend to execute cmd.exe by giving the .bat file as a command line argument.

Related

Process.Start() only works when started as release build within VisualStudio

I'm trying to do execute an external .bat by pressing a button.
The intention is to call some XCOPY instructions. Therefore I execute "sync.bat" using Process.Start(startInfo).
The output of that .bat is redirected to my App and shown in a dialog box. My code waits until the external call has finished.
echo "Batch SYNC started."
pause
xcopy "e:\a\*" "e:\b\" /f /i /c /e /y
pause
echo "Batch SYNC finished."
OK:
When I build my program as "release" and start it within VisualStudio2013, everything works fine (I see the Results, have to press ENTER in the black window, files are copied).
FAIL:
When I start my app by double-click (in file-explorer or from the desktop) or a debug build within the VisualStudio, I see the ECHO and the PAUSE output, but the batch did not stop and I see no results from XCOPY. Seems as if the PAUSE and XCOPY are killed immediately.
I got no exception and no entry in Windows-log.
I have tried to make DEBUG and RELEASE configuration identical (with no success).
Does anybody have an idea what I may do to get this simple function work outside the IDE?
Here is the code of the function called when the button is pressed:
private void ProcessSync_bat()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.FileName = "sync.bat";
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.Arguments = "";
startInfo.ErrorDialog = true;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
dlgFKSyncMessageBox.AddLine("----------sync.bat started-----------");
dlgSyncMessageBox.AddLine("===============Result================");
while (!exeProcess.StandardOutput.EndOfStream)
{
dlgSyncMessageBox.AddLine(exeProcess.StandardOutput.ReadLine());
}
dlgSyncMessageBox.AddLine("===============ERRORS================");
while (!exeProcess.StandardError.EndOfStream)
{
dlgSyncMessageBox.AddLine(exeProcess.StandardError.ReadLine());
}
exeProcess.WaitForExit();
}
}
catch (Exception exp)
{
dlgSyncMessageBox.AddLine("========EXCEPTION========");
}
}
Solution:
If I additionally set
startInfo.RedirectStandardInput = true;
then it works. I may redirect input from dialog window to the Process. Since I do not need any input for the intended XCOPY, this solution works for me without catching chars from the Dialog window and Forward to the process.
I can't see the logic, why I have to Redirect input too, but I'm glad that my Software now does what I need.

process.Start() not working in C# to call python script

Sorry if this is something obvious, I'm super new to C#.
I'm working on a program that runs a python script to check something online, that then writes it back to a file that C# reads and puts on a form. Everything works if I manually run them both at the same time, but I really want to start the script from the C# program.
Here's the function that should start the python script:
private void RunPython()
{
Process p = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "python " + path + "\\foo.py";
p.StartInfo = startInfo;
p.Start();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// get things set up... etc.
RunPython();
}
I've tried running it without the window hidden, and it just brings up an empty cmd line in the 'path' directory. Is it never running the python script? It doesn't seem like it is, but it may also be running it and immediately closing it. I can't tell.
I need it to stay open for the duration of the C# program's run, so if the problem is it exiting when the RunPython() method returns, is there some different way I could go about this?
Thanks!!
If you want to run a program in the command line using arguments to cmd.exe you need the /c flag. Alternatively you can use /k but that keeps the command process running which you probably don't want.
/c Carries out the command specified by String and then stops.
So it's usage is cmd.exe /c [string]
Try changing your arguments line to:
startInfo.Arguments = "/c \"python " + path + "\\foo.py\"";
See here for more information about running cmd.exe and dealing with quotes in the string section of the command: https://technet.microsoft.com/en-us/library/cc771320(v=ws.11).aspx

C# Change folder and start process in CMD, wait for it to finish

I need to open an external process from my Windows Forms app. What's more, I need to do it several times during the app's run time. Basically, I'm executing a .exe file with arguments several times from the command prompt, however I need to change the folder to where the .exe is in order for it to work properly.
So far, I'm opening the cmd like so:
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
Then using the process.WriteLine to feed commands to the CMD.
process.StandardInput.WriteLine("Awin.exe -X " + filePath + "/" + fileNumber + " ID=\"" + id + "\"");
And I need t do this for several fileNumber files. Also, I need to wait for the process started from the input to end before going on to the next one.
Is there a better way to do this, because I'm not getting good results from using process.WaitForExit
ProcessStartInfo class has a WorkingDirectory property.
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.WorkingDirectory = your_directory
(...)
//do your thing
Process process = Process.Start(processStartInfo);
Arguments can be passed via the Arguments property

Execute BATCH script in a programs memory

I am currently faced with a problem, I need to execute a batch script within a programs memory (so it does not have to extract the batch file to a temporary location).
I am open to solutions in C# and C++
Any help would be appreciated
cmd.exe won't run a script from the memory of your process. The options which seem most obvious to me are:
Relax the constraint that stops you extracting the script to a temporary file.
Compress your script into a single line and use cmd.exe /C to execute it. You'll need to use the command separator &&.
Write your own batch command interpreter.
Use a different scripting language.
Options 3 and 4 aren't really very attractive! Option 1 looks pretty good to me but I don't know what's leading to your constraint.
Open a pipe to the command shell and write the program code into that pipe. Here is an example: http://support.microsoft.com/default.aspx?scid=kb;en-us;190351
In C# it's an easy way to use System.Diagnostics for the job.
How!?
Basically, every batch command is an .exe file so you can start it in a separate process.
Some code:
using System.Diagnostics;
static void Main()
{
Process batch;
batch = Process.Start("ping.exe", "localhost");
batch.WaitForExit();
batch.Close();
batch = Process.Start("choice.exe", "");
batch.WaitForExit();
batch.Close();
batch = Process.Start("ping.exe", "localhost -n 10");
batch.WaitForExit();
batch.Close();
}
If you don't want to start every command in a separate process the solution is with a simple stream redirection.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"cmd.exe"; // Specify exe name.
startInfo.UseShellExecute = false;
startInfo.ErrorDialog = false;
startInfo.RedirectStandardInput = true;
//
// Start the process.
//
Process process = Process.Start(startInfo);
string[] batchFile = {"ping localhost", "ping google.com -n 10", "exit"};
int cmdIndex = 0;
while (!process.HasExited)
{
if (process.Threads.Count == 1 && cmdIndex < batchFile.Length)
{
process.StandardInput.WriteLine(batchFile[cmdIndex++]);
}
}
What's a good way to write batch scripts in C#?

How to send series of commands to a command window process?

We have a few commands(batch files/executables) on our network path which we have to call to initialize our 'development environment' for that command window. It sets some environmental variables, adds stuff to the Path etc. (Then only whatever working commands we type will be recognized & I don't know what goes inside those initializing commands)
Now my problem is, I want to call a series of those 'working commands' using a C# program, and certainly, they will work only if the initial setup is done. How can I do that? Currently, I'm creating a batch file by scratch from the program like this for example:
file.Writeline("InitializationStep1.bat")
file.Writeline("InitializeStep2.exe")
file.Writeline("InitializeStep3.exe")
Then the actual commands
file.Writeline("Dowork -arguments -flags -blah -blah")
file.Writeline("DoMoreWork -arguments -flags -blah -blah")
Then finally close the file writer, and run this batch file.
Now if I directly execute this using Process.<strike>Run</strike>Start("cmd.exe","Dowork -arguments"); it won't run.
How can I achieve this in a cleaner way, so that I have to run the initialization commands only once? (I could run cmd.exe each time with all three initializers, but they take a lot of time so I want to do it only once)
As #Hakeem has pointed out, System.Diagnostic.Process does not have a static Run method. I think you are referring to the method Start.
Once you have completed building the batch file, then simply execute it using the following code,
Process p = new Process();
p.StartInfo.FileName = batchFilePath;
p.StartInfo.Arguments = #"-a arg1 -b arg2";
p.Start();
Note that the # symbol is required to be prefixed to the argument string so that escape sequence characters like \ are treated as literals.
Alternative code
Process.Start(batchFilePath, #"-a arg1 -b arg2");
or
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = batchFilePath;
processStartInfo.Arguments = #"-a arg1 -b arg2";
Process.Start(processStartInfo);
More information
Process.Start method
Example of multi command batch file
dir /O
pause
dir
pause
Save this file as .bat and then execute using the Start method. In this case you can specify the argument with the command in the batch file itself (in the above example, the /O option is specified for the dir command.
I suppose you already have done the batch file creation part, now just append the arguments to the commands in the batch file.
Redirecting Input to a process
Since you want to send multiple commands to the same cmd process, you can redirect the standard input of the process to the take the input from your program rather than the keyboard.
Code is inspired from a similar question at: Execute multiple command lines with the same process using C#
private string ProcessRunner()
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
if (process != null)
{
process.StandardInput.WriteLine("dir");
process.StandardInput.WriteLine("mkdir testDir");
process.StandardInput.WriteLine("echo hello");
//process.StandardInput.WriteLine("yourCommand.exe arg1 arg2");
process.StandardInput.Close(); // line added to stop process from hanging on ReadToEnd()
string outputString = process.StandardOutput.ReadToEnd();
return outputString;
}
return string.Empty;
}
The method returns the output of the command execution. In a similar fashion, you could also redirect and read the StandardOuput stream of the process.
The Process.Run method that you mentioned, is that from the Process class in System.Diagnostics namespace? AFAIK, the Process type doesn't have either a static or instance method named Run. If you haven't already I'd try with the Start method on Process, either instance or static

Categories