Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancel a process while it is running

I run a process that executes an exe in command line with arguments and it takes time to finish. In the meantime, I show a form as dialog with a progress bar and a cancel button. When the cancel button is pressed the process should abort/stop. I have two ways to do it:

A. Declare a public static object of Process class in main form and abort it from progress form when cancel button is clicked:

public partial class frmMain : Form
{
    public static Process Process = new Process();

    public static bool ExecuteCommand(string sCommandLineFile, string sArguments)
    {
        Process.StartInfo.FileName = sCommandLineFile;
        Process.StartInfo.Arguments = sArguments;
        Process.StartInfo.CreateNoWindow = true;
        Process.StartInfo.UseShellExecute = false;
        Process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

        Process.Start();
        Process.WaitForExit();
    }
}

And close/abort process from Progress window form:

public partial class frmProgress : Form
{
    private void btnCancel_Click(object sender, EventArgs e)
    {
        frmMain.Process.Close();
        frmMain.Process.Dispose();
    }
}

B. Or do not call Process.WaitForExit(); and instead use Process.HasExited to check if the process is running and cancel it if cancel button is clicked:

public static bool IsCancelled = false;

Process.StartInfo.FileName = sCommandLineFile;
Process.StartInfo.Arguments = sArguments;
Process.StartInfo.CreateNoWindow = true;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

while (!Process.HasExited)
{
    Thread.Sleep(100);
    Application.DoEvents();

    if (IsCancelled)
    {
        Process.Close();
        Process.Dispose();
    }
}

public partial class frmProgress : Form
{
    private void btnCancel_Click(object sender, EventArgs e)
    {
        frmMain.IsCancelled = true;
    }
}

What is the right way to do it?

like image 764
Computer User Avatar asked Oct 29 '13 12:10

Computer User


1 Answers

A mix of the two.

public partial class frmMain : Form
{
    public static Process Process = new Process();

    public static bool ExecuteCommand(string sCommandLineFile, string sArguments)
    {
        Process.StartInfo.FileName = sCommandLineFile;
        Process.StartInfo.Arguments = sArguments;
        Process.StartInfo.CreateNoWindow = true;
        Process.StartInfo.UseShellExecute = false;
        Process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

        Process.Start();
        // Process.WaitForExit(); // Don't wait here, you want the application to be responsive
    }
}

And in the cancel handler

private void btnCancel_Click(object sender, EventArgs e)
{
    frmMain.Process.Close(); // or .Kill()
    frmMain.Process.Dispose();
}

Of course now you need a way of finding whether the process has exited the normal way. Use Process.HasExited regularly to poll for termination. Best to use a timer for this. I'm not currently sure, but there might even be an event for this.

Your second solution has the problem that it is actively waiting for the process to finish while still blocking the user interface. And it is using Application.DoEvents() which you should avoid by all means because it creates all kinds of nasty side effects (for instance you will be able to have the same code run several times in a recursion).

like image 101
PMF Avatar answered Oct 20 '22 10:10

PMF