I really do want to write some entries about handling async APIs as I recently promised, but I’ve been engaged in hand-to-hand combat with some installer issues recently, so for now–a post about installers.
Installation of both Adobe AIR itself and AIR applications is done via Windows Installer–more commonly referred to as MSI. Using MSI is the doing the "right thing", but it certainly isn’t the easy thing.
One of the most frustrating aspects of MSI is that its internal model is opaque. I can only assume it’s terribly complicated; it certainly isn’t documented. And while usually the inner workings of a technology can be gleaned not only from documentation but also its API, the MSI API is itself rather convoluted. Whether that’s because the underlying model is convoluted or just obscuring that model I just don’t know.
(By the way, for a great discussion of internal models of operation and how they’re surfaced in everyday things like refrigerators, check out Don Norman’s classic, "The Design of Everyday Things".)
With that introduction, here’s my best attempt at a partial explanation of how features are selected for installation or removal during an MSI install operation. At the very least this will serve to document what I just spent several hours figuring out.
Every feature has a level assigned to it, the level being a non-negative number. Unless you override the defaults, MSI will install every feature with a level of one. A feature with level zero is never installed, and in fact setting a feature level to zero can be a dangerous thing to do–but that’s a topic for another post. Features with higher numbers can be installed by changing the INSTALLLEVEL property, but that’s not what this post is about either so no more on that topic.
You can also change the set of installed features using a set of properties. There are many of these, but for my purposes I’ll stick with just ADDLOCAL, REMOVE, and REINSTALL. Once you set one or more of these properties the level-based behavior above no longer applies. Instead, very feature listed in ADDLOCAL is installed, and every feature in REMOVE is–well, removed. Features in REINSTALL are essentially patched–if they’re installed.
Now, you might be wondering about REINSTALL, since it sounded like we were talking about install scenarios–not patches. But–and here’s one of those strange parts of the MSI model–in MSI, any "installation" can add, remove, or patch features. In other words, what you might naively call installs, patches, and uninstalls.
(To make things even weirder, other parts of MSI are inconsistent about this. For example, the "msiexec" command line tool does, as the model would predict, allow you to uninstall a product using the /i (install) option. But it also has a /x (uninstall) option. The latter would seem to suggest that the model included a notion of uninstalling, but I’m pretty sure it doesn’t. The API, for example, doesn’t have an uninstall function–products are typically uninstalled by calling MsiConfigureProduct. Go figure.)
Let me illustrate with a simple scenario. Suppose I have a product P with three features, F1, F2, and F3:
To install both features I can either (a) not set any properties, because they’ll be installed by default or (b) set ADDLOCAL=F1,F2,F3.
If I want to install just F1 and not F2 or F3: ADDLOCAL=F1.
Finally, suppose F1 and F2 are installed (but not F3) and I wish to patch F1, install F3, but uninstall F2: ADDLOCAL=F3 REMOVE=F2 REINSTALL=F1.
So there you have the essence of the model; an install operation is really a set of install, uninstall, and patch operations. Of course there’s more to it than that, as there are different ways to install features, etc. And that’s why this entry is titled a "partial explanation."
A note in closing: The log files generated by msiexec are your friend for debugging MSI issues; use /lv*x to get the most information. If you’re debugging issues related to feature selection like I describe here, look for entries with this form:
Feature: Runtime; Installed: Local; Request: Reinstall; Action: Reinstall
They’ll give you a good idea of which operations MSI thinks you’ve requested, including the state of the feature before the operations begin.