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:
- User clicks on ‘check for updates’ option
- We start a new thread which will do the whole updating process
- We check if the new version is available and inform the user about the result
- The user decides if he want to download the newest version
- We download the installer and save it somewhere on the disk
- We ask the user if he wants to install it now
- We save the path to the installer file in the registry or in the config file (we will need it later)
- We run the installer and terminate our program
- The installer should have an option to launch the application after the installation is complete (and this option should be enabled by default)
- Our application is started by the installer
- Now is the good time to remove the downloaded file and remove the entry from registry or config file
- 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
I was always looking for a code which does this. I am just a beginner to #.net. I had build a basic webvigor.com in .net then i switched to PHP. Thanks for sharing this.
Great text and very usefull. Thank’s and keep writing.
Thanks a lot man.
Great tutorial and help me alot.
Keep doing tutorials like these.
Awesome…
I’m not a corporate-level programmer, so I’m not as familiar with Delegates and Threads as I should be. But this post has done a lot to help me understand them better.
I kept what you wrote in mind as I developed the update code for my program.
Thanks again for your posts!
Hi, nice posts there 🙂 thank’s for the interesting information
Nice post, thanks very much. I will definitely try this out to see how it works for me.
Coherent and structured tutorial with first rate examples. Thanks a million!
thanks a lot mate.
i’m having only one (so far) problem with this:
The installer thread starts, but the existing application remains running until AFTER the setup.exe has initiated. As a result, the installer sees the existing application in-use and offers “Repair / Remove” options rather than the normal installation routine.
i would REEEEALLY appreciate help on this, as i’d like to apply this method to all our in-house projects. Please let me know if i can send you a .cs file or something to see what i’m doing.
Thanks VERY much for the tutorial!
Hi Joe,
I already explained this in my email, but I’ll repeat it here (maybe someone else will have similar problem):
– the installer does not check if your application is running; however it can encounter locked files during install and complain about it
– the installer offers repair/remove options if you run the msi for the same version that is already installed in the system
Thanks, this helps a lot!
BTW, where is the WebRequest code to download the msi file? Or am I missing something???
Thanks,
Peter
Peter,
Well, my fault. Although there is “how to download” in the title of this blog entry, I’ve decided to skip this step to keep the tutorial simple 🙂 Downloading is pretty straightforward:
1) create the WebRequest with the installer address
2) use its request.GetResponse method to get the response (it will throw an Exception in case of HTTP error)
3) check the response.Headers to get the content-length
4) create the temporary file
5) read the response stream and save the installer to the temporary file (you can call ShouldStop method every 8K to check if the user canceled the action)
6) in case of any errors – remove the temporary file
If everything went OK, we launch the installer
Greetings,
mech
Thanks a lot, it was usefull.
Hello Mech, thank you for such a great tutorial. I am new to threading in .Net so I am struggling with one part of your example.
In the CheckForNewVersion() and DownloadInstaller() functions, you have the following comment: use this.ShouldStop while checking so the thread can be interrupted: if this.ShouldStop() throw new ThreadInterruptedException(“”);
I understand what this is suppose to do, however, I am not sure how to properly implement this. Would I just add this to the top of my checkforversion/download code in each function or is there another way to properly implement this?
I saw your comment on Feb 22nd about calling this every 8K during download. Was unsure how to do this properly.
Thanks in advance for your help.
Hello TheKidd,
I’ll try to keep my explanation simple:
1) the main app thread (the UI thread) lanches the worker thread that will look for the new version and download it
2) For various reasons (the user pressed the cancel button on our check for updates dialog or closed our app) the main thread wants to finish the worker thread; to do so, it should call the StopThread (refer to the source in this tutorial). The StopThread method sets the stopping event and waits for the thread to stop
3) Now the worker thread won’t stop until it finishes its work. But we cannot wait until it finishes the whole operation if we want to cancel it. So the worker thread should call the ShoudStop method (and it should do it quite often). If this method returns true, the worker thread simply finishes its work:
if (ShouldStop()) return; // that’s all
Of course you should do the cleanup if the thread created some temporary files or has some open files/connections. You can do it before the return statement or in thread’s ‘finally’ section.
When I wrote in my comment about calling the ShouldStop method every 8K, I meant something like this (metacode):
while (!download_finished)
{
if (ShouldStop())
{
//cleanup
return;
}
result += read_8192_bytes_from_stream
}
If you have any further questions – please contact me.
Greetings,
mech
CAn you put all together in solution with all code and Sample Windows Forms Application for test Updater ?? thx
espinete,
I’ve just created a simple example project, you can download it here: http://themech.net/downloads/CheckForUpdateExample.zip . It will check for the new version and ask the user if he want to download it. This is just a quick example, so it will download the Eyes Relax installer.
Anyone knows a way for displaying a progress indicator while downloading the update?
Thanks a lot for this nice programm.
I’ve certainly saved a few days
RvdH: You create the WebRequest and get the response. The response headers should contain the “content-length”, which is the total installer size. Now, in the loop you read the installer from the reponse stream and update the progress bar based on total length and the downloaded bytes counter. You just should be careful about the threads: if you create the progress bar in the main UI thread and download the installer in the background, the progress bar should be updated by the main thread (f.e. the backgound thread calls the main thread delegate using BeginInvoke in order to update the progress bar).
By this example, I process all the steps. That steps are also executed successfully. But my software is not updated.
Please can you help me for that process.
Please it is very urgent.
Thanks,
Manisha
Do you have a WPF version? It seems WPF does not have an Invoke or BeginInvoke call but I don’t know enough about how Dispatch works to translate that part of the code.
No, I didn’t use WPF but as far as I know you can use Dispatcher, which has the BeginInvoke/Invoke methods