UAB & Add/Remove Programs

Topics: Updater Application Block
Nov 7, 2003 at 11:58 AM
originally posted by: JamesCadd

I'm using an msi installer for my app and I'm wondering how the extra files and directories created after automatic updates can be removed. What about extra registry keys, etc. that can be added using a post-processor? Thanks in advance!
Nov 8, 2003 at 8:21 AM
originally posted by: JeffDeville

The updater will automatically clean up files that it no longer needs. Very slick. I'd be interested in knowing if the log files can be cleaned over time as well though. (Maybe keep the last 5 logs or something).
Dec 8, 2003 at 9:35 AM
originally posted by: JamesCadd

This is incorrect, the updater does not automatically clean up files.

For anyone looking for an answer to my original question & using windows installer to package their product, here's some help. This can be accomplished by creating your own installer class that overrides Uninstall. In the override, just delete all files in the application directory. Finally, add your installer as a custom action in your windows installer project.
Dec 8, 2003 at 3:51 PM
originally posted by: wsabey

thanks Jim, do you have a reference to an artice that has an example of overriding uninstall or would you mind sharing a portion of your class? have not worked with actions, is it as simple as adding the component created for the installer class we create?

a side question about installer in case you might know - When a user goes to install a new msi for the next version of our application installer stops with the msg: "Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product use Add/Remove Programs on the Control Panel"
Why can't the new install remove the old version or prompt the user to allow it to uninstall?
Dec 9, 2003 at 2:28 PM
originally posted by: JamesCadd

There are a few good articles on custom actions in the Deployment Walkthroughs section of the MSDN docs. Here's a link:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxwlkwalkthroughcreatingcustomaction.asp

When you create the custom installer class (I use the VS template) it derives from System.Configuration.Install.Installer. This class lets you override Install, Commit, Rollback and Uninstall. By the way, be careful about functions like "OnAfterInstall"; it actually seems to run before the override of Install. I usually choose to add the custom installer class to the project that it does installation on. To get the installer to run that code, right click on the setup project and go to view/custom actions. Then, right click on the actions you want to use and go to add custom action. For my project, I select the primary output from the project that contains the installer class. Looks like each project can only have one installer class so VS locates it in the application project without trouble.

As for the side question, the installer can automatically remove the old version of the app for you. Select the setup project and hover over the properties tab (don't right click the project and choose properties). Set RemovePreviousVersions to true and setup will behave the way you want.

A side caution about versions and the updater. Unless you're doing it manually (and I'd love to know how its done), when the updater downloads new versions of your app, windows installer has no idea that the version has changed. So let's say the user originally installed version 1.0 and the updater brought the app to 2.0. Now the user finds an old MSI on their disk for version 1.5 of the app and tries to install it. The installer would remove what it thought was version 1.0 and install version 1.5. Not sure what to do about that, any ideas?
Dec 9, 2003 at 5:25 PM
originally posted by: wsabey

thanks again. To use Remove Previous Versions I also had to increment the version field or it gave me the same msg.

another question, though. I am fixing the subfolder name under application folder to be the version nbr of the install. Have you found a way for the install to derive that automatically from assembly info?

Good question about the version differences between install packages and updater. Maybe somebody who knows Whidbey could tell us if it will be handled in the next generation?
Dec 10, 2003 at 8:18 AM
originally posted by: JamesCadd

Hey, glad I could help. I don't know of any way for the installer to fix that subfolder name. I ran into the same issues with versioning, and here's what I did.

First, I decided that the version number shouldn't come from the application's main assembly. I figured I may want to update just my secondary "utility functions" assembly and call that collection of files the next version of my app.

My next issue was that I want to distribute updates as cabinet files. Clients downloading cabs from the server and extracting them sounds good for a number of reasons. I started out by embedding the version number in the file name (ie. "App Update 1.5.0.1.cab"), but I don't like that solution. If you make a cabinet deployment project in VS, select it and hover over properties you'll see there is a version field, which I decided to use for versioning the updates & the application. The value of the field shows up in a file packaged in the cabinet - randomly named with .osd extension (note - this file is xml but it's not well formed, can't just do an XmlDocument.Load("1234.osd") ). Also, this solution isn't perfect because some files need to be outside the cabinet on the server (my custom post processor dll, MS.AB.AU.dll and MS.AB.AU.Interfaces.dll).

It would be convenient to include the primary output from this cabinet project in the setup project. Then, when the app is installed, a custom action can create a directory named after the version and extract the cabinet file there. This is basically what I did, except instead of naming the directory after the version number I always call it "Initial Install". I didn't have any good reason for doing that, just preference.

The short of it is I think you could create a custom action to determine the version that's getting installed and move the files around or rename the directory.

A word of caution about moving around files during installation. MSI keeps track of where files were supposed to end up after an install & checks this when you click the shortcut to your application from the start menu. If you've moved any files MSI goes into resiliency mode and will automatically attempt to uninstall/repair the app. To keep this from happening use the Orca tool (windows installer sdk) to edit the MSI after its built. First, in the Files table, look under the FileName column for the files that will be moved during install and note the values in the Component column. Then in the Component table, find the rows for the files by matching up the Component value. For each row, clear out the value in the KeyPath column. Save the MSI and you can now safely move files around during install.

Another word of caution about working with cabs. There is no good way to extract/create them from managed code, and I can't find any help for it online. Download the cab sdk and you'll see some documentation about extracting/creating cabinets with cabinet.dll (comes with windows). These functions are very hard to interop with as they require allocating memory for the extraction and of course there are GC concerns when doing this in managed code. The header files for the dll are so old they have a define for CHICAGOM6HACK. However, you can redistribute extract.exe and cabarc.exe with your app (these do not come with windows) to work with the cabs. I decided to go this route and I'm fairly pleased with it.
Dec 13, 2003 at 3:17 PM
originally posted by: wsabey

Thanks for the tips. Could you please elaborate on the good reasons you find for installing with cabs?

Back to removing files. After an autoupdate, how did you remove the previous version directory? via a postprocessor?
Dec 15, 2003 at 7:45 PM
originally posted by: JamesCadd

My motivations for using cabs were based on updater side of the application. Primarily, I wanted the client app to download compressed files. Using cabs also keeps IIS file mapping from interfering with downloads. The decision to use cabs in the .msi for the app seemed convenient since I was already building cabs for the updates.

I chose not to remove previous versions (no good reason for that). Just my 2 cents but I don't think you should remove previous versions in the post processor. I wrote another post about how unreliable post processing is, and I try to do as little of it as possible.
Jan 7, 2004 at 11:11 AM
originally posted by: wsabey

Jim,
I haven't had a chance to get to removing the files yet. Would you mind sharing any of your uninstall class?
Bill