Getting a Process to terminate - c#

I have a process object setup like the following:
Process p = new Process();
p.StartInfo.FileName = command;
p.StartInfo.UseShellExecute = true;
p.StartInfo.Arguments = String.Format(
commandArguments,
destinationLocation,
sourceLocation,
sourceDirName,
(string.IsNullOrEmpty(revisionNotes.Text)) ? "" : revisionNotes.Text);
(where undefined values are supplied externally to this code and are valid). The process in question launches and properly executes with p.Start(); but i need to catch it on termination. The console window flashes up briefly and goes away which would seem to indicate that the process is done, but none of the relevant events are fired (OutputDataRecieved, Exited, etc) and it's like the process never ends. (I'm trying to execute a lua script with some parameters if that's relevant). Can someone help me get this process to stop correctly?

WaitForExit

Have you set the EnableRaisingEvents property of the process to True? You won't catch the Exited event without it.

Related

Program freezes after clicking button?

When I click a button, the program freezes.
I am trying to reach file.bat in h folder of the root directory.
this is my code for click event:
private void button1_Click_1(object sender, EventArgs e)
{
{
string pathName = textBox.Text;
pathName = Path.GetFileName(pathName);
string dir = System.Windows.Forms.Application.StartupPath;
string dirEnd = dir + "\\h\\";
Process proc = new Process();
proc.StartInfo.FileName = "CMD.exe";
proc.StartInfo.Arguments = "\"" + dirEnd + "file.bat" + "\"";
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();
proc.WaitForExit();
MessageBox.Show("Program has been started!");
}
If I remove proc.WaitForExit(); nothing will happen but the program wont freeze.
But if I remove proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; the CMD will start but the argument wont be passed to it.
Process.WaitForExit();
From the docs:
Instructs the Process component to wait indefinitely for the associated process to exit.
This means that the Process.WaitForExit(); method blocks until the process finishes. If the process runs for a long time your application will just wait, it's not actually frozen, it's just doing what it's told.
If you don't actually want to wait for it to finish and show your message instead just remove the statement like this:
proc.Start();
MessageBox.Show("Program has been started!");
Edit
There's something wrong with your argument. While debuging, remove proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; and proc.WaitForExit(); so you can see what happens.
Build your argument string in a seperate variable and inspect it to make sure it's correct.
If you want to run a command with cmd.exe, you need to pass the /C argument. For example: cmd.exe ping won't work, you must use cmd.exe /C ping. In your case the argument should probably be something like: /C path/to/file.bat.
This line will make your program hang:
proc.WaitForExit();
You will never get to the messagebox showing because the application is waiting for your process to exit. Just remove proc.WaitForExit() and your message will show while the process is still running in the background. However, if you do this you have to make sure everything is handled properly (i.e. process dies when your application closes)
According to MSDN, WaitForExit waits for the associated process to exit, and blocks the current thread of execution until the time has elapsed or the process has exited. 'The current thread' being the thread that you launched it from; in this case, your main program, causing your hang.

Loading bar while cmd.exe is running

What I'm trying to do:
Pass a command to .cmd, show a loading bar while the command executes, exit cmd and display a message box after progress bar is full
What's happening:
When I click the button that sends the command, the application hangs, the command is executed, but CMD never exits after it's finished, so the application remains frozen (until I manually close cmd.exe). I also have no idea how to display a loading bar while the command executes. When the loading bar is full, that's when I'll display the message box.
My code:
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.WorkingDirectory = #"C:\"
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
p.StandardInput.WriteLine(Command_That's_Called);
^ Which gets executed upon a button_Click event.
Things I've tried:
p.WaitForExit(); // still hangs
Also threading, but I got an error like "accessed from thread other than one it was created on".
Regarding CMD not closing, I'd just kill it after a certain amount of time, but it the length of time for the command to complete depends on various things.
To exit the CMD process after it finished to execute the command, try to add "/C" at the beginning of your process arguments:
p.StartInfo.Arguments = "/C (your arguments)";
If you type "cmd /?" in the command prompt, you'll find that "/C: Carries out the command specified by string and then terminates".
About to add a LoadingBar, you need to learn about BackgroundWorker class

Wait properties windows dialog before continue script

I had a piece of code to display the properties window of a file,
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = #"C:\Users\nyongrand\Desktop\Internet Download Manager.lnk";
psi.Verb = "properties";
Process process = Process.Start(psi);
process.WaitForExit(); //This give me exception, Object reference not set to an instance of an object.
what I want is to wait until the window properties is closed, because if my code closed the properties window will be closed as well, I need a solution between, my code is able to wait for the properties window closed, or my code can exit without closing the properties window.
The exception you're getting means that process is null at the time you try to call its WaitForExit member method. So the question you should be asking is why.
Start with the documentation for the overload of the Process.Start function that you're calling to see what it actually returns. Sure enough, it returns a Process object, but only under certain conditions:
Return Value
Type: System.Diagnostics.Process
A new Process component that is associated with the process resource, or null if no process resource is started (for example, if an existing process is reused).
And, from the "Remarks" section:
Note: If the address of the executable file to start is a URL, the process is not started and null is returned.
So, if an existing process is re-used, the Process.Start method will return null. And you cannot call methods on null.
Try replacing
Process process = Process.Start(psi);
with
Process process = new Process();
if(process.Start(psi))
{
process.WaitForExit();
}
else
{
//Do something here to handle your process failing to start
}
The problem you face with your code is that Process.Start() returns a Boolean. It's not a factory for Process objects.

Understanding how to control stdout using System.Diagnostics.Process

I see several questions about how to launch processes and push data into stdin, but not how to control where their output goes.
First here is my current code, run from a console mode C# application:
// Prepare the process to run
ProcessStartInfo start = new ProcessStartInfo();
// Enter in the command line arguments, everything you would enter after the executable name itself
start.Arguments = " -";
// Enter the executable to run, including the complete path
start.FileName = "doxygen.exe";
// Do you want to show a console window?
start.WindowStyle = ProcessWindowStyle.Normal;
start.CreateNoWindow = false;
start.RedirectStandardInput = true;
start.UseShellExecute = false;
// Run the external process & wait for it to finish
using (Process proc = Process.Start(start))
{
//doxygenProperties is just a dictionary
foreach (string key in doxygenProperties.Keys)
proc.StandardInput.WriteLine(key+" = "+doxygenProperties[key]);
proc.StandardInput.Close();
proc.WaitForExit();
// Retrieve the app's exit code
int exitCode = proc.ExitCode;
}
What happens when I run this is I do not see any new window (though I think I should) and all of doxygen.exe's stdout is printed to my app's console window.
What I would like to happen is one of two things:
Doxygen is launched in a visible window, and I can see its stdout in that window, not in my app's window.
Doxygen is launched in a hidden window, and it's stdout is written to a log file.
How can I achieve these?
In addition, why am I not getting a separate window for the spawned process, and why is the spawned process writing output to my window not its own?
One thing that you can do is use RedirectStandardOutput and instead of using WaitForExit you can use ReadToEnd
ProcessStartInfo start = new ProcessStartInfo();
start.RedirectStandardOutput = true;
//make other adjustments to start
Process p = new Process();
p.StartInfo = start;
p.Start();
string output = p.StandardOutput.ReadToEnd();
and then you can use string output at your leisure
If you want to get output in real-time the p.StandardOutput property has methods that allow you to get the output asynchronously. I don't know all the details to it offhand, I've only used it once before, but there's plenty of literature out there if you search for it.
Also be careful when redirecting both StandardOutput and StandardError at the same time, If they're long enough, it is possible for that to cause deadlocks.
You need to do two things:
1) Indicate that you want the standard output of the process to be directed to your app by setting the RedirectStandardOuput property to true in the process.
2) BEFORE the call to WaitForExit, start capturing the output:
string sOutput = p.StandardOutput.ReadToEnd();
If you do not start reading the output before calling wait for exit, you can encounter a deadlock.
However, it is important to know that standard output will only capture output information, not anything written to the standard error stream of the app.
In order to capture both streams of information, you can hook the process's OutputDataReceived and ErrorDataReceived events and write the event data directly into a log file or store it in a class property for use after the process has completed.

System.Diagnostics.Process not Exiting in Code

I have the following code which works well on another server. The problem is that the process never seems to make it to an Exited state. The exe being called creates a file as the last step and this file does get created but my code never seems to know that the process has completed. Also the exe being called runs in much less than 10 seconds when ran manually. My code looks like this:
System.Diagnostics.Process proc = new System.Diagnostics.Process() proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = exeConf.CMD;
proc.StartInfo.Arguments = argString;
proc.Start();
proc.WaitForExit(10000);
if(proc.HasExited)
msgLine = proc.StandardError.ReadToEnd();
See this MSDN article.
A deadlock condition can result if the parent process calls p.WaitForExit before p.StandardOutput.ReadToEnd and the child process writes enough text to fill the redirected stream. The parent process would wait indefinitely for the child process to exit. The child process would wait indefinitely for the parent to read from the full StandardOutput stream.
It seems as if Process.StandardOutput.ReadToEnd() has to be called immediately after Process.Start() else it could create a deadlock.

Categories