Paying for upgrades

No, this isn’t a post on the costs of proprietary software but an amplification/clarification to my previous post. On wix-users, there’s a thread on the pains of automating upgrades.

If your product consists of a large number of files and the file set changes regularly – files being added and removed during the product lifetime – it’s only natural to want to avoid the cost of hand-authoring setup changes to match. (A little over a year ago, I shipped a product with over 7000 files, so I’m familiar with the pain and desire for automation.)

Unfortunately, our frenemy the component rules makes such automation difficult. The closest we-the-WiX-team has gotten to a complete solution is to create components with one file each, which makes the component eligible to have its component GUID automatically generated (using an asterisk in the Component element’s Guid attribute value).

What doesn’t work is when files are removed. Windows Installer doesn’t let you remove components in a minor upgrade, so using one file per component doesn’t immediately solve the automation problem: Your automatically-generated minor upgrade will be missing a component, which is a mortal component-rule sin.

Nor can you avoid the problem by using multiple files per component because component rules say that components must be immutable: You can’t add or remove resources from a component.

So automating the creation of minor upgrades has additional costs:

  • Additional tooling to try to support removing files without blatantly violating component rules.
  • Additional coding in your product to tolerate “obsolete” files without being able to remove them.

For many types of apps, but especially Web apps with many content files, that’s a huge cost. Being able to ship minor-upgrade patches from an automated build might be a benefit worth the cost. It’s really a decision your team needs to make.

I’ll add that if you don’t anticipate shipping patches on a regular schedule, you might just automate the authoring of your RTM product and pay the price of manually tweaking your setup authoring when you need to ship a patch. Again, it’s a cost-benefit decision your team needs to think about.

Cheap and easy

If you don’t absolutely need to ship patches, you can avoid the costs of minor upgrades by simply using major upgrades. You can remove files without worrying about component-rule violations if you use an “early” scheduling of the RemoveExistingProducts standard action – before or immediately after the InstallInitialize action.

The MSI SDK notes that scheduling RemoveExistingProducts early is “inefficient” because the files that are same between the two product versions are removed and then reinstalled. But that inefficiency is what lets you remove files and components. If you schedule RemoveExistingProducts immediately before or after InstallFinalize, MSI implements the major upgrade by installing the new version of the product “on top of” the previous version, upgrading files with newer versions, then removing the previous version. MSI increments the reference count of components in both packages during the installation of the newer version, then decrements it during the removal of the previous version. Component reference counting works only if component rules are followed, so it’s pretty much the same as minor upgrades.

If you have a large product, the size and install-time benefits of minor upgrade patches might be worth the development effort. Otherwise, major upgrades scheduled early are a great solution. Your call.

Neither more nor less

‘When I use a word,’ Humpty Dumpty said, in a rather scornful tone,’ it means just what I choose it to mean, neither more nor less.’

‘The question is,’ said Alice, ‘whether you can make words mean so many different things.’

‘The question is,’ said Humpty Dumpty, ‘which is to be master – that’s all.’

Alice’s Adventures in Wonderland and brought to mind by almost anybody reading SDK documentation for any length of time

Windows Installer has three ways of upgrading products from one version to another:

  • Major upgrades
  • Minor upgrades
  • Small updates

There are two common problems we run into when discussing upgrades given size-related terms to describe upgrades.

Version numbers

Major and minor are also commonly used to refer to particular elements in a version number (major.minor.build.patchlevel being most common).

But major upgrades can upgrade any product version number to any other version number, regardless of which parts of the version number change. For example, the WiX installers are always major upgrades for every 3.0.xxxx version; only the build portion of the version number changes with each weekly build. And the WiX v3.0 installers don’t do major upgrades down to WiX v2; we intentionally designed the installers to be able to live "side-by-side" on the same system to help migrating from WiX v2 to v3.

Minor upgrades, on the other hand, are usually used to deliver service packs; they must change some part of the product version but can’t change the major part of the product version (at least according to PatchWiz.dll error ERROR_PCW_INVALID_MAJOR_VERSION).

Small updates cannot change the product version at all.

Size matters not

Major, minor, and small also bring to mind size or breadth of a particular upgrade. To an extent, that’s true: Small updates tend to be for single-purpose "hotfix" types of fixes. Minor upgrades can update many files but can make only limited "structural" changes such as adding features and components; they can’t be used to remove components.

Major upgrades aren’t so limited: They can change anything in a product, but also support as few changes as a small update. So even if you’re changing only a few files, you can still use major upgrades. Think of major as an upper limit on the set of changes, not the lower limit on the type of upgrade you need.

Major upgrades also have the advantage of built-in support in Windows Installer. Using Upgrade and UpgradeVersion elements, you can use a "naked" .msi package to install a product for the first time or by major-upgrading a prior version of the product. Doing the same thing with a minor upgrade requires a bootstrapper executable or extra work to set the REINSTALL and REINSTALLMODE properties appropriately.

Windows 7 MSI session at PDC

New/old lead program manager Tyler Robinson has a session at PDC to discuss the new features in Windows Installer and ClickOnce in Windows 7:

If you are a developer involved in the creation of application deployment packages using Windows Installer (MSI) or ClickOnce, this session is for you. Learn how you can take advantage of new features in Windows 7 to shorten application installation times, reduce UAC prompts, write less custom code, take less time to write installations for complex packages, and much more!

Not a lot of detail, but some potentially interesting tidbits. To see the information available on the session:

  1. Go to the PDC sessions page.
  2. Click on Windows 7.
  3. Scroll to the bottom of the list; it’s currently the sixth session from the bottom.

Why am I not linking directly to the session? AJAX and Web 2.0, baby. Not even Raymond Chen can make it happen.<sigh>

Hint: Be generous with upgrade codes

Major upgrades work across products by associating them with a single upgrade code: Version 1.0 of a product has a different product code than version 2.0 but both share the same upgrade code. The FindRelatedProducts action and MsiEnumRelatedProducts function find any products on the system with a particular upgrade code. The RemoveExistingProducts action then uninstalls the (usually older) products as part of the major upgrade cycle.

Note that FindRelatedProducts and MsiEnumRelatedProducts explicitly support finding multiple products installed on the system simultaneously. MSI doesn’t try to force you to use the same upgrade code only for products that are upgraded by major upgrades. That means it’s possible to use the same upgrade code for products that aren’t major upgrades for each other.

However, the Upgrade table supports only version and language as ways of narrowing down the products it finds. So if you use the same upgrade code for multiple products that can be installed simultaneously, FindRelatedProducts doesn’t have a way to filter out the ones you don’t want removed in a major upgrade.

You can use a custom action to remove product codes from the property specified by the UpgradeVersion/@Property attribute. Just schedule it to run after FindRelatedProducts. The cost is that you have to maintain by hand any such product codes and carry them from version to version.

The Upgrade table and FindRelatedProducts action let you search on multiple upgrade codes in a single product. So it’s always safe to use more upgrade codes if you think you might support having products side-by-side in the future — just use multiple Upgrade elements to detect and uninstall them via major upgrade.

In short, if you have products are never going to be installed at the same time, you can safely use the same upgrade code. But if you have products that might need to be installed simultaneously, give them separate upgrade codes. (Upgrade code GUIDs are cheap when you buy them in quantity from reputable online retailers.) And always test your servicing strategy before you release a product: Some things can’t be fixed in a patch.