I've an application which does
Process.Start()
to start another application 'ABC'. I want to wait till that application ends (process dies) and continue my execution. How can I do it?
There may be multiple instances of the application 'ABC' running at the same time.
I think you just want this:
var process = Process.Start(...);
process.WaitForExit();
See the MSDN page for the method. It also has an overload where you can specify the timeout, so you're not potentially waiting forever.
Use Process.WaitForExit? Or subscribe to the Process.Exited event if you don't want to block? If that doesn't do what you want, please give us more information about your requirements.
I do the following in my application:
Process process = new Process();
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.ErrorDialog = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
process.Start();
process.WaitForExit(1000 * 60 * 5); // Wait up to five minutes.
There are a few extra features in there which you might find useful...
You could use wait for exit or you can catch the HasExited property and update your UI to keep the user "informed" (expectation management):
System.Diagnostics.Process process = System.Diagnostics.Process.Start("cmd.exe");
while (!process.HasExited)
{
//update UI
}
//done
I had a case where Process.HasExited didn't change after closing the window belonging to the process. So Process.WaitForExit() also didn't work. I had to monitor Process.Responding that went to false after closing the window like that:
while (!_process.HasExited && _process.Responding) {
Thread.Sleep(100);
}
...
Perhaps this helps someone.
Process.WaitForExit should be just what you're looking for I think.
Referring to the Microsoft example:
[https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.enableraisingevents?view=netframework-4.8]
Best would be to set:
myProcess.EnableRaisingEvents = true;
otherwiese the Code will be blocked.
Also no additional properties needed.
// Start a process and raise an event when done.
myProcess.StartInfo.FileName = fileName;
// Allows to raise event when the process is finished
myProcess.EnableRaisingEvents = true;
// Eventhandler wich fires when exited
myProcess.Exited += new EventHandler(myProcess_Exited);
// Starts the process
myProcess.Start();
// Handle Exited event and display process information.
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {myProcess.ExitTime}\n" +
$"Exit code : {myProcess.ExitCode}\n" +
$"Elapsed time : {elapsedTime}");
}
Like Jon Skeet says, use the Process.Exited:
proc.StartInfo.FileName = exportPath + #"\" + fileExe;
proc.Exited += new EventHandler(myProcess_Exited);
proc.Start();
inProcess = true;
while (inProcess)
{
proc.Refresh();
System.Threading.Thread.Sleep(10);
if (proc.HasExited)
{
inProcess = false;
}
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
inProcess = false;
Console.WriteLine("Exit time: {0}\r\n" +
"Exit code: {1}\r\n", proc.ExitTime, proc.ExitCode);
}
Try this:
string command = "...";
var process = Process.Start(command);
process.WaitForExit();
Related
I have a problem with my PictureBox after executing a process. At the time I call the process, that just executes a batch file, the PictureBox (displaying a GIF animation) freezes.
I want to click the button that starts the process and show the PictureBox displaying the GIF animation, and after the process is done I want to hide the PictureBox.
Does anyone know how to achieve this?
Here's my code:
// My executeCmdCommand
public void executeCmdCommand(string argument)
{
var arg0 = argument; // Path
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C " + arg0;
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
}
private void button1_Click(object sender, EventArgs e)
{
DisplayImage();
string cmdCom = #"C:\Users\Mim\Desktop\test.bat";
executeCmdCommand(cmdCom);
HideImage();
}
private void DisplayImage()
{
imageControl.Show();
//PictureBox imageControl = new PictureBox();
imageControl.Width = 400;
imageControl.Height = 400;
Bitmap image = new Bitmap(#"C:\Users\foobar\Desktop\loading.gif");
imageControl.Dock = DockStyle.Fill;
imageControl.Image = (Image)image;
Controls.Add(imageControl);
}
private void HideImage()
{
imageControl.Hide();
}
The problem lies on this line of code inside your executeCmdCommand() function:
process.WaitForExit();
Take a look at what the documentation says about this method:
Process.WaitForExit Method | Microsoft Docs
Sets the period of time to wait for the associated process to exit, and blocks the current thread of execution until the time has elapsed or the process has exited. To avoid blocking the current thread, use the Exited event.
So, you should not call this method if you want the UI thread unblocked till the end of the external process execution. But if you still want to be warned when the process ends, then you can use the Exited event as suggested on the documentation.
You can found an example of the use of the Exited event, and another ideas, here:
Windows Form run external process without blocking UI - Stack Overflow
I would add only one thing to the answer that I've just linked: If you are going to hide your PictureBox inside the event handler called by the Process.Exited event, you should set a reference of your Form to the Process.SynchronizingObject property (documentation), otherwise your event handler can (mostly probably) be executed on a thread different from your UI thread, causing an error when accessing anything from your Form, including the controls.
The code could be like this:
using System.Diagnostics;
public void executeCmdCommand(string argument)
{
Process process = new System.Diagnostics.Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = $"/C {argument}";
process.StartInfo = startInfo;
process.EnableRaisingEvents = true;
process.SynchronizingObject = this;
process.Exited += (sender, e) => {
HideImage();
};
process.Start();
//process.WaitForExit();
}
I want to run Iperf via c#
when running via cmd everything works fine and fast
but I run it via c# using this code :
public void RunProcess(string FileName, string Arguments, bool EventWhenExit )
{
process = new Process();
process.EnableRaisingEvents = true;
process.OutputDataReceived += new DataReceivedEventHandler(OnDataReceivedEvent);
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.LoadUserProfile = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = FileName; // Gets or sets the application or document to start.
process.StartInfo.Arguments =Arguments;//Gets or sets the set of command-line arguments to use when starting the application
Thread.Sleep(1000);
if (EventWhenExit)
{
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(myprocess_Exited);/*New line */
}
process.Start();
process.BeginOutputReadLine();
PID = process.Id;
}
private void myprocess_Exited(object sender, EventArgs e)
{
process.Refresh();
Thread.Sleep(2000);
onProcessEnd(this, "ENDOF " + Proc.ToString());
Console.WriteLine("Process exsiting ");
}
private void OnDataReceivedEvent(object sender, DataReceivedEventArgs e)
{
string OutputFromProcess = e.Data;
//fire event to event handler class for further use
onDataOutputFromProcess(this, OutputFromProcess, Proc.ToString());
}
I get wrong strange behavior :
when running 1 stream (those of you who use Iperf will know...) every works fine in console and my application (winform)
but I run 3 streams and above , my application wont go over and than just hangs when it should exit
what can be the problem ?
what can be a good work around this problem ?
First you should avoid using Thread.Sleep(x) at any cost.
And i assume you are not using a backgroundWorker or a new Thread to execute the IPerf processes?
I think the backgroundworker would work well for you. Take a look here
In addition:
A cmd program is in most cases very linear.
A WinForm program not. You have to sepereate GUI and Work-Thread.
the GUI is only for Input and Display. Everthing else you should do in another Thread, because otherwise you will block the GUI.
I am processing a Tex file by starting a Process like this one:
process p1 = new Process();
p1.StartInfo.FileName = "C:\\texlive\\2012\\bin\\win32\\pdflatex.exe";
p1.StartInfo.Arguments = FileName;
p1.consuleProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.consuleProcess.StartInfo.CreateNoWindow = true;
p1.consuleProcess.StartInfo.RedirectStandardOutput = true;
p1.consuleProcess.StartInfo.UseShellExecute = false;
p1.consuleProcess.StartInfo.RedirectStandardInput = true;
p1.Start();
p1.consuleProcess.BeginOutputReadLine();
p1.consuleProcess.OutputDataReceived += new DataReceivedEventHandler(p1_OutputDataReceived);
I display the output strings in a TextBox by handling OutputDataReceived event.
If there were an error in the Tex file, a line should be written in StandardInput. I think there is no event that can tell me, when the process is waiting for an input; So I thought, I can check OutputDataReceived event to see when the condition: e.Data == "?" is true. But, the problem is that the StandardInput needs an input, just before firing OutputDataReceived event with e.Data=="?"
So, what can I do to see when the process is waiting for an input?
thanks.
Not sure if this is what you mean but are you after something like
p1.WaitForInputIdle(NumberofMilisecondstoWait)
Update:
Maybe something like this
public void test()
{
p1.OutputDataReceived += new DataReceivedEventHandler(p1_OutputDataReceived);
}
void p1_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
throw new NotImplementedException();
}
In C#, I can start a process with
process.start(program.exe);
How do I tell if the program is still running, or if it closed?
MSDN System.Diagnostics.Process
If you want to know right now, you can check the HasExited property.
var isRunning = !process.HasExited;
If it's a quick process, just wait for it.
process.WaitForExit();
If you're starting one up in the background, subscribe to the Exited event after setting EnableRaisingEvents to true.
process.EnableRaisingEvents = true;
process.Exited += (sender, e) => { /* do whatever */ };
Process p = new Process();
p.Exited += new EventHandler(p_Exited);
p.StartInfo.FileName = #"path to file";
p.EnableRaisingEvents = true;
p.Start();
void p_Exited(object sender, EventArgs e)
{
MessageBox.Show("Process exited");
}
Be sure you save the Process object if you use the static Process.Start() call (or create an instance with new), and then either check the HasExited property, or subscribe to the Exited event, depending on your needs.
Assign an event handler to the Exited event.
There is sample code in that MSDN link - I won't repeat it here.
Take a look at the MSDN documentation for the Process class.
In particular there is an event (Exited) you can listen to.
I have a c# GUI app and it's running a bunch of command line process one after another. How do I end/kill the app while the command line process is running?
I have an Exit button (button 3) but it's not working if the process called is still running.
private void Run_Process(string process_to_run, string p_arg)
{
Process myProcess = new Process();
richTextBox1.AppendText("\nRunning " + process_to_run);
try
{
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = process_to_run;
myProcess.StartInfo.Arguments = p_arg;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
myProcess.WaitForExit();
richTextBox1.AppendText("...Success");
time_date = get_time();
log_file.Write(time_date);
log_file.WriteLine(process_to_run + "...Success");
}
catch (Exception ep)
{
richTextBox1.AppendText("\n" + ep.Message);
time_date = get_time();
log_file.Write(time_date);
log_file.WriteLine(process_to_run + "...Failed. ERROR: " + ep.Message);
}
}
private void button3_Click(object sender, EventArgs e)
{
db.connection.Close();
Application.Exit();
}
Right now, you're waiting for the process to exit:
myProcess.WaitForExit();
If this is happening in the UI thread, then you won't be able to exit (cleanly) until the method finishes, which means you have to wait for the process to finish.
If, instead, you don't wait on the process, you'll be able to exit immediately.
You should be able to rework your logic to not block by setting Process.EnableRaisingEvents and then subscribing to the Exited event on the process. You can add your text to your RichTextBox in this event, instead of blocking the main thread.
You have a call to myProcess.WaitForExit(); in Run_Process. If Run_Process gets called from the main thread, you're going to block that thread until the command line tool finishes. That means button3_Click() can't fire until after myProcess has completed.
If you need to exit, and exit now, try Environment.Exit.
Environment.Exit Method
Terminates this process and gives the underlying operating system the specified exit code.
Environment.Exit(1); really works.