Previously I gave a high-level introduction to the WiX and MSI technologies. I'm going to dig a little bit deeper here and get a bit closer to the nuts of bolts of these technologies. Note that I'm not intending to give you an introduction to the details of writing WiX installers, the tutorial I linked to previously (which is also linked in from the main WiX site) does that quite well enough. I do think that there is some context you will need before you start that tutorial and that's what I'm aiming to give you here.
Features and Components
We are all used to seeing screens like this during an installation:
These are features, in MSI (and WiX) terminology. A feature consists of a number of components and very little else. Components can be used by more than one feature.
A component is uniquely identified by a GUID and consists of a number of resources that get installed (or uninstalled) together. The list of resources that Windows Installer can deal with natively is:
|Files and folders ||Registry keys || Environment variables |
|Entries in an INI file ||ODBC drivers and data sources || Windows services |
|Shortcuts ||Assemblies || |
This is clearly a limited list - missing resource types include X.509 certificates, web sites, SQL databases, etc, etc. Fortunately Windows Installer offers an extensibility mechanism.
Custom actions are the way that Windows Installer let's MSIs do things other than just installing the above resource types. There are a variety of types of custom actions and these all need to be explicitly ordered and scheduled by the MSI developer. The main custom actions that I've used consist of running an executable, running some code in-process (i.e. via a DLL which is embedded in the MSI) and do some manipulation of properties.
Somebody authoring an MSI package is most likely using some environment or other (e.g. WiX) and this environment will typically provide some custom actions. Cleverly, some of these custom actions look like additional resource types to the MSI developer. For instance, WiX itself provides facilities to install and uninstall the following:
|COM and DCOM components ||X.509 certificates ||Device drivers |
|Event logs ||File shares ||SQL databases |
|SQL scripts ||Users and groups ||IIS web sites |
|IIS virtual directories ||Entries in XML files ||Visual Studio help files |
|COM+ applications ||MSMQ queues || |
Custom actions are not intrinsically linked to components or features. This means that you don't have a convenient event to hook into so that, say, you can run a particular executable once some files have been installed. Instead, all custom actions can have conditions attached to them which detail whether or not the custom action should execute.
So if you want an executable to run once some files have been copied, you need to set a condition on the custom action which runs the executable. This condition would ensure that the custom action executed only when the particular component (or feature) containing the files was being installed. You would also need to schedule the custom action so that it occurred after the installation of the files.
Note that it's rare that you will author just one custom action to modify system state. Once you have done this, you need to give some thought to rolling back the action if the install fails, as well as uninstalling the action (strictly speaking you should also worry about rolling back the uninstall!). So you'll usually write them in pairs or triples.
Properties are just variables within your MSI package. They can have a default value or a value can be supplied on the command line by the user. Initial values can also be obtained by scanning the file system (e.g. to look for a particular file or directory), by using environment variables or by scanning the registry. You can also build up property values from other properties, but you need to use a custom action to do this.