Stopping Automation

  • Thread starter Thread starter bjm
  • Start date Start date
B

bjm

I am writing a program that will automate a series of application
installations. I want to give the user the option of stopping the
program's execution in between installations (for example, give the
user the chance to stop the program after the second installation
before it continues on to the third installation). However, I want the
user to be able to start the installations and walk away as well, so I
can't ask the user if he wants to continue if that means execution will
stop and wait for his response. I thought of two ways to do this,
though there may be a better way I'm not thinking of.

First, I could have a button on my program's Form that says "Stop
Installation." I tried doing this, and having that button's click
event simply set a flag that says to stop execution after the current
installation. However, when an installation starts, I get an hour
glass and I am unable to hit the button that I created. If this is
going to work, I need to find a way to continue allowing the user to
enter input even while the program is running an installation (with the
Process class).

Second, I could pop up a dialog asking the user if he wants to
continue, which closes after X number of seconds without a response. I
think this would work, but I'm new to C# and I haven't found a
relativly easy way of doing this.

Does anyone have an idea of how I could accomplish this? Thank you in
advance!
 
Hi,

The first idea sounds much better IMO (stop button). I don't think your
problem has to do with the Process class at all. It probably has to do with
the fact that you're blocking the UI thread. Perhaps you're calling
Process.WaitForExit()? The following code should work fine:

// 2.0 Framework code

Process process = new Process();
process.StartInfo.FileName = @"C:\Install.msi";

// anonymous method
process.Exited += delegate(object senderP, EventArgs eP)
{
// this code is executed when the process terminates

int returnValue = process.ExitCode;
};

process.EnableRaisingEvents = true;
process.Start();

// let the thread return to the caller so that the UI is responsive

If you're using the 1.* Framework then you can register an event handler
with Exited to do the same thing as a above but without the anonymous part.
 
You're completly right, the Process.WaitForExit was blocking the
thread. I like this idea of using the Process's Exited event.
However, I need to wait until the current installation is finished
before starting the next one, so I need another way of accomplishing
the same effect as WaitForExit while not blocking the UI thread so I
still allow user input. I tried setting a flag in the exited event
handler (I am using 1.1 Framework) and then placing a while(flag is not
set) in the UI code, but after a few seconds of this while loop, the
program goes unresponsive and doesn't come back up, even after the
installation completes. How can I wait for the current process to exit
while not blocking the UI thread so that I can still recieve user
input? Thank you very much for your help!
 
Hi,

You don't want a while loop in the method that starts the process. What you
need is for that method to return to the caller A.S.A.P.

You can use a Queue to hold the list of processes that must be started in
the order that they must be executed:

private readonly System.Collections.Queue processQueue =
new System.Collections.Queue();
private bool cancelled;

When your program starts, create all of the process objects that it needs
and enqueue them in the correct order (first-in-first-out):

void InitializeProcesses()
{
processQueue.Enqueue(CreateProcess("calc"));
processQueue.Enqueue(CreateProcess("msconfig"));
processQueue.Enqueue(CreateProcess("msinfo32"));
}

Process CreateProcess(string fileName)
{
Process process = new Process();
process.StartInfo.FileName = fileName;
process.EnableRaisingEvents = true;
process.Exited += Process_Exited; // 2.0 delegate inference syntax
return process;
}

Add an event handler for the Exited event and use the following method:

void Process_Exited(object sender, EventArgs e)
{
RunNextProcess();
}

Then create a method that will dequeue the next process and start it:

void RunNextProcess()
{
if (cancelled || processQueue.Count == 0)
// The entire process may be cancelled and
// since the last process has an event handler for Exited
// this method will be invoked even though there are
// no more processes to be executed, so we check
// the Count and exit when it's zero
return;

Process process = (Process) processQueue.Dequeue();
process.Start();
}


When you want to begin the first process simply call RunNextProcess() and
return to the caller. As long as you never call RunNextProcess from a
background thread you don't have to worry about thread-safety here since the
processes will be started serially by the Exited event.

To cancel the process set the cancelled field to true. If you want you can
store the currently running process in a field so that you can call
CloseMainWindow on it as well. I haven't added code to allow you to reset
the entire operation, though, so you'll want to encapsulate this code in an
object if that behavior is required.
 
That should work great. Thank you very much!!

Dave said:
Hi,

You don't want a while loop in the method that starts the process. What you
need is for that method to return to the caller A.S.A.P.

You can use a Queue to hold the list of processes that must be started in
the order that they must be executed:

private readonly System.Collections.Queue processQueue =
new System.Collections.Queue();
private bool cancelled;

When your program starts, create all of the process objects that it needs
and enqueue them in the correct order (first-in-first-out):

void InitializeProcesses()
{
processQueue.Enqueue(CreateProcess("calc"));
processQueue.Enqueue(CreateProcess("msconfig"));
processQueue.Enqueue(CreateProcess("msinfo32"));
}

Process CreateProcess(string fileName)
{
Process process = new Process();
process.StartInfo.FileName = fileName;
process.EnableRaisingEvents = true;
process.Exited += Process_Exited; // 2.0 delegate inference syntax
return process;
}

Add an event handler for the Exited event and use the following method:

void Process_Exited(object sender, EventArgs e)
{
RunNextProcess();
}

Then create a method that will dequeue the next process and start it:

void RunNextProcess()
{
if (cancelled || processQueue.Count == 0)
// The entire process may be cancelled and
// since the last process has an event handler for Exited
// this method will be invoked even though there are
// no more processes to be executed, so we check
// the Count and exit when it's zero
return;

Process process = (Process) processQueue.Dequeue();
process.Start();
}


When you want to begin the first process simply call RunNextProcess() and
return to the caller. As long as you never call RunNextProcess from a
background thread you don't have to worry about thread-safety here since the
processes will be started serially by the Exited event.

To cancel the process set the cancelled field to true. If you want you can
store the currently running process in a field so that you can call
CloseMainWindow on it as well. I haven't added code to allow you to reset
the entire operation, though, so you'll want to encapsulate this code in an
object if that behavior is required.
 
Back
Top