In one of the previous tutorials I described a simple solution that allows an application to check if a new version is available. The solution presented there has two major flaws:

  • while doing the check the main application thread is blocked, thus making the application UI not responsive to user actions
  • after finding a new version the user had to download and install it manually

A moderately skilled C# programmer should be able to solve these two problems easily. So in this tutorial we will learn how to implement our ‘check for updates’ option in a more advanced way. We will work with threads, events and delegates.


Solution description

In the previous tutorial we implemented a method that checks if the new version of the application is available. This was done by downloading an XML document containing the info about the newest version of the software. Now we’ll improve this.
I make the first assumption here – our application is distributed within an installer (msi or exe file). This will make the installation process easier – instead of downloading separate files and replacing them while doing the update, we will just download and run a single installer file and let it take care of the whole upgrading process.
We have to modify the XML document from the previous tutorial by adding an URL of the installer. This way our application will know where to download the installer from.
Our solution will work as follows:

  1. User clicks on ‘check for updates’ option
  2. We start a new thread which will do the whole updating process
  3. We check if the new version is available and inform the user about the result
  4. The user decides if he want to download the newest version
  5. We download the installer and save it somewhere on the disk
  6. We ask the user if he wants to install it now
  7. We save the path to the installer file in the registry or in the config file (we will need it later)
  8. We run the installer and terminate our program
  9. The installer should have an option to launch the application after the installation is complete (and this option should be enabled by default)
  10. Our application is started by the installer
  11. Now is the good time to remove the downloaded file and remove the entry from registry or config file
  12. And we’re done

More information about creating an installer can be found here.

Working with threads

By default a Windows Form application is single-threaded. That means that if we do a time-consuming operation in the ‘onclick’ method, the application won’t process any other messages and the user interface will be blocked. That’s why longer tasks should be run in separate threads.
Starting a new thread is very easy. Write a new method that does all things you want to run “in the background”. Now create a new Thread object passing your method as a parameter and call the Start method to start the new thread. The Start call will return immediately and the method you passed will be executed in the new thread.
The code we run in the background may take some time to complete and an impatient user can click “check for update” for the second time. We shouldn’t start another thread in this case, so we check if the updating thread is already running.
Here is our method that starts a new thread:


using System.Threading;
public partial class Form1 : Form
{
 //...
 private Thread m_WorkerThread;
 private void checkForUpdatesButton_Click(object sender, EventArgs e)
 {
  // check if the thread is currently running
  if ((this.m_WorkerThread != null) &&
   this.m_WorkerThread.IsAlive)
   return;
  this.m_WorkerThread = new Thread(this.WorkerThread);
  this.m_WorkerThread.Start();
 }
}

Invoke/BeginInvoke

Now our code is being executed nicely in the background. But eventually it will have to interact with the user (telling him that something went right/wrong or asking him to make a decision). Usually we would simply call a form method updating the user interface. But this would break a very important rule: updating the user interface element must take place on the thread that created the UI element. For simplicity we assume in our solution that the whole user interface runs in the main UI thread. So instead of calling a form method that updates the interface, we have to let the form know that we want its method to be executed (by the main thread). Two Control class methods do exactly what we want: Invoke and BeginInvoke.
Both methods execute a delegate on the UI thread of that control. So we take a method we want to be executed in the UI thread, wrap it with a delegate and call Invoke/BeginInvoke. The difference between these methods is that Invoke waits until the UI thread has finished executing the delegate (and it return the value that delegate returned), while Control.BeginInvoke returns immediately. So if we have to wait for the result, we call Invoke. But when there is no need to wait/block – BeginInvoke is preferred.
Here is the example of using Invoke:


private delegate bool OurDelegate(bool newVersion);

private void WorkerThread()
{
 bool newVersion = this.CheckForNewVersion();
 bool downloadIt = (bool)this.Invoke(
  new OurDelegate(this.OnAskUser),
  new Object[] { newVersion });
 if (!downloadIt) return;
 //...
}

private bool OnAskUser(bool newVersion)
{
 if (!newVersion)
 {
  MessageBox.Show("No updates available", "Check for updates");
  return false;
 }
 return DialogResult.Yes ==  MessageBox.Show(
  "Download new version?", "Check for updates",
  MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}

Stopping a thread

We know how to start a thread. But in some situations (f.e. when the user is closing our application) we should be able to stop it before it completes its work. We can do it using two events (the first indicates if the event should be stopped, and the second indicates the it is stopped). When we want to finish the thread, we set the first event. Periodically (for example in every iteration, if we have a time-consuming loop) our thread should check if this event is set. If it’s set, it event terminates and indicates it by setting the second event. Here is the code:


ManualResetEvent stopThread=new ManualResetEvent(false);
ManualResetEvent threadStopped=new ManualResetEvent(false);

private void checkForUpdatesButton_Click(object sender, EventArgs e)
{
 //...
 this.stopThread.Reset();
 this.threadStopped.Reset();
 this.m_WorkerThread.Start();
}
public void StopThread()
{
 if ((this.m_WorkerThread != null) && this.m_WorkerThread.IsAlive)
 {
  this.stopThread.Set();
  while (this.m_WorkerThread.IsAlive)
  {
    if (WaitHandle.WaitAll(
     (new ManualResetEvent[] {this.threadStopped}),
     100,true))
    {
     break;
    }
    Application.DoEvents();
  }
 }
}
private bool ShouldStop()
{
 //this method is called by a thread
 //to check if it should stop executing
 if (this.stopThread.WaitOne(0, true))
 {
  this.threadStopped.Set();
  return true;
 }
 return false;
}

Installing the new version

Now the installer. I wrote a little tutorial about creating MSI package, so I assume you have the installer. So if the user decides that we should install the new version, we do it. First (in the background thread) we download the installer using WebRequest and save it on the hard drive (Path.Combine(Path.GetTempPath(), "OurApp.msi") seems to be a good choice). Now we use BeginInvoke to call the method that will install it. This method just executes the installer and terminates the application (so the files we want to overwrite in the installed are not locked). Here is that method:


private void ExecuteInstaller(string filePath)
{
 try
 {
  Process.Start(filePath);
  //save the filePath (in a config file/registry)
  //and delete that file next time the application is started
  this.SaveFilePathToDelete(filePath);
  Application.Exit();
 }
 catch (Exception)
 {
  File.Delete(filePath);
  MessageBox.Show("Error executing the installer");
 }
}

The installer should launch our application when the instalation process is finished.

Putting the pieces together

I’ve put all the code presented here in the example. Note that the code for checking for the new version and downloading it was explained the a separate tutorial and was not included in the example.
Summing things up: nowadays users don’t want to download and install every new version manually. Doing those things automatically is both simple and useful. If you have any questions or I made some mistakes here – please, don’t hesitate to comment the article.
download the sample project
mech