Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a .net program update itself?

Tags:

.net

I've written a program that updates itself if it finds a newer version on a server but I'm finding it hard to implement cleanly.

Checking a remote server and downloading the file are easy enough but then what? It can't simply File.Copy("newversion.exe","myprogram.exe") because myprogram is running and the file is locked.

I do it by downloading two files newversion and update. myprogram then launches update and exits. update waits for two seconds, does the copy, then launches myprogram (which is now the updated version) and exits. myprogram looks for update when it starts and deletes it and newversion if it finds them. mypogram is now the new version with no files left laying around.

There must be a better way than this so what's the .net way for a program to update itself?

PS. Sorry if this question appears twice - I got a 'stack overflow is broken' page the first time I submitted it.

like image 354
mrh1967 Avatar asked Oct 22 '09 21:10

mrh1967


2 Answers

See if ClickOnce Deployment gives you what you need.

like image 178
Philip Wallace Avatar answered Oct 11 '22 19:10

Philip Wallace


I looked at both Wix and ClickOnce and didn't love them. I wanted something simpler, for one-file "xcopy deployment" type WPF apps.

So I built one. It's an AppUpdater class that you can drop into any WPF app, automatically updates itself when necessary.

Checking for a version number and downloading the latest version is easy.

The next part is less easy. How do you replace a running app? The approach I took was this:

  • every time it runs, the app checks a well-known URL for a version. If the version is NOT later than the version of the currently executing app, then there's nothing more to do.

  • If the version IS later, then the app grabs a named Mutex, copies itself (Assembly.GetExecutingAssembly().Location) to a temporary location, then starts a new process (process #2) from that temp location, passing a command-line argument that says "you are trying to update" and giving the original exe location.

  • process #1 shuts itself down.

  • process #2 starts up - it sees that it is trying to update, so it downloads the updated image, and places it in the original location (the location that was passed on the command line). Rather than waiting 2 seconds, or any arbitrary time, it uses the named Mutex to determine when process #1 has exited.

  • process #2 then starts process #3 - using the original location.

  • Process #2 shuts down, releasing its named Mutex.

  • process #3 starts up. It checks the version URL - sees that it is current. No update necessary. Process #3 also waits for process #2 to release its Mutex, and then removes the temporary copy of the EXE - the one that was used by process #2.


EDIT

In response to the comment, yes, it sounds complicated. But the logic that does all that is in the AppUpdater module. To use it from a WPF app is pretty simple:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        // add this line in your constructor
        if (UpdaterCheck())  this.Hide();
    }

    // this is all boilerplate
    private Ionic.AppUpdater.Wpf.Updater _updater;
    private string _manifestUrl = "http://example.org/AppUpdates/MyApplication/Manifest.xml";
    private string _infoUrl     = "http://example.org/MyApplication.html";
    private string _description = "MyApplication is a delightful application; it does x, y, and z. ";
    // Obtain the publicKey XML from the ManifestTool that ships with Ionic AppUpdater.
    // The following string is Ionic's public key.  You will need a different one.
    // Consult the Readme for more information.
    private string _publicKeyXml = "<RSAKeyValue><Modulus>sZqhvF0KX6m4blah..blah...=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

    // add this boilerplate method
    private bool UpdaterCheck()
    {
        _updater = new Ionic.AppUpdater.Wpf.Updater("This is MyApplication.",
                                                    _infoUrl,
                                                    _description,
                                                    _manifestUrl,
                                                    _publicKeyXml);
        return _updater.Status.IsUpdating;
     }
    ...

Details and code you can run, here.

It works only with WPF apps, but it would be pretty simple to build a WinForms version of the thing. Same idea, though some of the logic that generates the UI would have to change.

like image 34
Cheeso Avatar answered Oct 11 '22 17:10

Cheeso