So how do you make an updater be less horrible.
First off, as I suggested for all applets, consider not having one at all. For instance, Collectorz.Com's applications each check for updates periodically when they are started. That way you bury your update functionality with the application, and it alleviates the need to worry about external updaters.
If your application is itself a plugin (think Flash, Quicktime, Java or a driver (of any kind)), then you don't have a convenient application on which to hang your updater. For that case, whatever you do, don't burn a process whose sole purpose is to check for updates once a month. Instead, use the task scheduler functionality built into Windows to schedule your updater. The task scheduler is a remarkably flexible mechanism for scheduling periodic operations. Even using the Task Scheduler 1.0 interfaces (which are available on Windows platforms going back to Windows ME), you can generate triggers that will cause tasks to be run daily, weekly, monthly, monthly on a specific day of the week, logon, idle, etc. For Vista, the list of trigger types is enhanced to include triggers on system events, groups of triggers, etc.
One of the cool things you can do with scheduled tasks is to specify the context in which the job runs - jobs can be scheduled to run in the context of the user at the console, in the system context, the context of an interactively logged on user, to run only if a specific user is logged on, etc.
Using the task scheduler means that you can get your updater to run without consuming any long-term resources.
Once you've decided that you need to update the application, you've got to download the update. For that, you really have two options. The first is that you can assume that the user is going to want the update and pre-download it, the second is that you download it after informing the user about update. For either case Windows has a nifty feature called "BITS" which allows you to download data from the web without interfering with the user - essentially the BITS service is aware of the traffic generated by the interactive user and it throttles its transfers if it detects that the user's using the network. It also supports progressive downloading so it can handle the network dropping out mid transfer. Windows Update's downloader is built on top of BITS, but I'm not aware of any 3rd party apps that use it (which is a shame, because it really is cool). BITS is available on at least Windows XP and later, so it's not "yet another vista-only feature".
Also, whatever you do, don't ever require elevation for your updater - I cannot imagine any scenario that would require that your updater run elevated - it just annoys the user who complains about unnecessary elevation prompts.
Next: Mitigations for notification area handlers.
One problem I had with BITS is that it only considers the local network adapter when determining when the connection is "idle". The problem with that is, my network adapter is 100 Mbit, but my internet connection is much slower than that. So even if I'm downloading a file at "full" speed, BITS sees that much of my "network connection" is idle and tries to download as well.
Looking at the documentation, though, that seems to be fixed in BITS v3 -- included with Windows Vista. I think I've got UPnP turned off, though, so maybe it's time to enable it :-)
> I cannot imagine any scenario that would require that your updater run elevated
Uh, this one lost me. I write my installer to install in Program Files. Surely that means my updater must update files (DLLs, EXEs, say) in Program Files? Ergo, elevation, no?
A great Media Center program, <a href="http://www.tvtonic.com">TVTonic</a>, basically a video podcast client, uses BITS.
That is pretty much what i implemented for the application i work on, the IT guys for our clients were getting annoyed with always having to run updates on the locked down machines, so i implemented a system utilizing Duncan McKenzie's BITS wrapper for .Net.
The application checks for available updates at startup on a background thread and if available it initiated a BITS job. When an update is available and downloading an icon appears in the toolbar at the right hand side (a la the original firefox) and the user can click on it to see the status.
It downloads a valid MSI package and utilizing the wixcab.dll i have it so that it extracts the files from the MSI and updates the software when the app is closed (giving the user 5 seconds to skip the update, as well as a button to allow them to not have to wait). Using the official MSI gives less chance of versioning issues as we only have to deploy 1 update package (with a price of slightly larger downloads).
There are two caveats
1) All users have to have full control to the program directory but thats not toooooo bad and can be configured at install time).
2) Some machines seem to have a problem with BITS and i am still debugging those issues.
Oh and naturally the automatic updating can be disabled :)
"Windows Update's downloader is built on top of BITS, but I'm not aware of any 3rd party apps that use it (which is a shame, because it really is cool)"
Maybe this is because it wasn't cool enough to be documented...
There are at least 3 apps that use BITS besides Windows and Office. RSS Bandit is one of them.
See http://en.wikipedia.org/wiki/Background_Intelligent_Transfer_Service for details.
If you're installed in the Program Files folder, how could you possibly update yourself WITHOUT elevation on Vista?
Marvin, I included the link to the BITS documentation.
jon: You can check to see if an update is available without elevation, then elevate only if an update is needed.
Re not requiring an elevation prompt for updates, you might be able to do it with this: http://msdn2.microsoft.com/en-us/library/aa372388.aspx
That page is rather confusing, but I do remember seeing something about administrators being able to specify applications that are allowed to be patched by non-administrators using digital certificates and so on...
Is there a reason Windows Update doesn't use the suggestion you make here? It runs as a service, instead of using the task scheduler. I assume there is a good reason for that, and knowing that reason might be a good indicator why third party ISVs also do it that way.
"...BITS, but I'm not aware of any 3rd party apps that use it."
The launchpad application of the StarWars Galaxies MMO uses BITS to start downloading the files for the next update a few days before it officially goes live.
'Uh, this one lost me. I write my installer to install in Program Files. Surely that means my updater must update files (DLLs, Exes, say) in Program Files? Ergo, elevation, no?'
Julian, but why would you restrict your user to install only to Program Files?
If a non-admin user installs to some other location, he/she will have write permissions for that directory for future updates too.
If an admin install to Program Files, he/she already has the necessary permissions for future updates and the updater may only run in the elevated context.
I am down with all programs which require admin users for installation, only because their setup has %programfiles% hard-coded as the base directory. Half of my line of business programs don't run under user accounts because they constantly write to the installation directories which unfortunately lie at %programfiles%.
As some examples: Flashget won't save download information for files because it writes to [installationdirectory]\default.jcd which is usually in %programfiles%. Firefox fails to update by non-admin users because it too goes to %programfiles%. My bug tracking software fails to connect to server because it writes credentials to a file in installation directory, which again is in %programfiles%.
That is not just for programs out there in the wild; Microsoft products do have that problem too. Any ASP.Net project that uses IIS must be opened in Visual Studio running under admin account, do run-as, privilege escalation whatever! MSN messenger displays only an update notification that tells to login as an admin.
And Dean, Microsoft does not follow the guidelines they have laid out for others themselves.
>> but I'm not aware of any 3rd party apps that use it
well, we do :-) ( http://www.die.de/docs )
Even if the application is installed in Program Files, I don't see any reason why a well-designed updater should need elevation at all - it can execute in the system context to actually perform the installation (assuming the file transfer is itself secure, and/or you check for a valid digital signature on the download).
1) Use Task Scheduler to launch your update-checker on occasion. The update-checker deals with Internet resources, so should ideally run with limited privileges.
2) If an update is found, download it via BITS, and then trigger your actual update process in a context with high privileges (e.g. LocalSystem) via Task Scheduler.
3) If you want to block on user input (e.g. to accept the upgrade and begin installation), launch a separate, low-privilege process in the user(s) context for the UI. This would signal back to the high-privilege process a simple "proceed/cancel" message (hence limited attack surface).
4) The high-privilege updater process would either exit if it gets the cancel message, or proceed with the installation (verifying that the digital signature of the update is both yours and the file integrity is good, so the file cannot be faked by another publisher).
5) During the update, which is done by the high-privilege non-interactive process, you could optionally post progress updates back to the low-privilege UI process if you want the user to be aware of the status.
Tanveer, that's not necessarily true if an Administrator installed the program on behalf of someone else. Using signed v4 MSIs that have been designed for user patching is a really good solution to this. Alternatively, if you are using the Task Scheduler approach, you can arrange for the task to be created in a context which does have the necessary rights.