开发者

How can a .net program update itself?

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 th开发者_JS百科is 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.


See if ClickOnce Deployment gives you what you need.


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.


You could use WIX or ClickOnce. They handle it for you.


Its easy when you know the "workaround". Your program cant download itself over itself because the file is locked by the running process. The workaround is that it still is possible to RENAME the file. So here is what you do:

IF your programs name are "myprogram.exe":

  1. myprogram.exe starts
  2. Myprogram.exe download a new version of itself but under the name "newversion.bak"
  3. Check that newversion.bak has downloaded correct (md5-check or something)
  4. myprogram.exe renames the "myprogram.exe" to "myprogram.old"
  5. myprogram.exe renames the "newversion.bak" to "myprogram.exe"
  6. myprogram.exe restarts itself, and voila, its updated.
  7. (optional) myprogram.exe deletes "myprogram.old" if exists when started.

This will allow you to update your program without having an external updater.


You may want to look into .NET's No Touch Deployment. It was replaced, in marketing at least, by Click-Once.

I wrote an application that used this. It pulled its assembly from a local intranet server. It used sockets to listen to a specific port, so I was able to force upgrades by sending a message, which spawned another program to kill it/restart it. Probably not the best solution but it worked.

I'd say Click-Once is a better solution, but I thought I'd mention No Touch.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜