Tao of the Windows Installer, Part 2

Sticking strictly to the "approximately weekly" schedule, here we have, nearly two weeks later, the somewhat more substantial second part in this series.

Thanks for the comments on Part 1 - even though I briefly answered some at the time, I'll be using these when I come to re-draft the list. So, please keep the comments coming, they are useful.

Series links:

Packaging Rule 7: Work On a Copy
"My file server won't boot and I really need it up and running now!""Ok, let's re-install Windows and restore the data from backup.""What backup ...?" Been there? Done that? While losing a single MSI package might not be as disastrous as losing your file server, you really don't want to start from scratch because of some accidental corruption. So, always make a copy of your package before you start work, then work on the copy. That way, it is easy to revert to a known good version if the working one becomes corrupt or has other problems you cannot easily correct.
Rule 8: Never Cancel a Package Build Before it Finishes
To avoid corrupting a package, allow the packaging tool to finish building any new version once initiated. Even if you realise that you need to make more changes or did something wrong, allowing the package to build rather than stopping part way through helps avoid possible corruption. Obviously, if the package does become corrupt, all is not lost if you followed Rule 7.
Rule 9: Use a Clean System for Repackaging

If you are repackaging an existing application rather than creating your own original package, then it is important to do this on a “clean” system. Repackaging tools commonly use “snapshots” of the system state before and after the legacy application is installed, then create an MSI package based on the differences. To avoid any extraneous changes making their way into the packages the systems should:

  • Match the target system as closely as possible.
  • Be clear of any unnecessary applications
  • Have all non-essential system services stopped
  • Have all unnecessary processes stopped

Some limitations of repackaging are discussed in the following article: INFO: Disadvantages of Repackaging Applications In addition to this, you should check with 3-rd party vendors what their support policy is for repackaging their applications. It is possible that you will void any support agreement if you do not use the vendor-supplied installation mechanism.

Rule 10: Do Not Repackage Microsoft Updates
Microsoft uses a different packaging technology to create Service Packs and other updates for many products, including Windows, Internet Explorer, Exchange Server, SQL Server and ISA Server. This technology is not related to the Windows installer and it is completely unsupported to convert the updates to Installer packages. Refer to the following article for support details: Repackaging software updates to use Windows Installer is not supported You may be aware that Windows Service Packs ship with an “Update.msi” package that can be used to deploy the Service Pack via Group Policy. This package simply calls the normal .exe-based install as a custom action. This is the only supported use of this package and it is not supported to create your own similar MSI wrapper for Service Packs or other updates. Apart from the one situation mentioned, deploying updates in this way is not tested by Microsoft and the results cannot be guaranteed and hence are unsupported.
Rule 11: Do Not Repackage MSI-Based Applications
The Installer does not just copy files and registry keys to the target system. It also creates a lot of “configuration data” to help it keep track of the components, features, etc. If you use a “snapshotting” technique to repackage an MSI-based application your package will include all of this extra data, which it will treat as normal files and registry information. However, this will almost certainly lead to serious problems with the Installer, since this data is actually Installer data from another install.
Rule 12: Modify Vendor Packages Using Transforms
As previously mentioned vendor may not support re-packaging their legacy packages. It is also possible that they will not support direct modification of their MSI packages either. For example, Microsoft does not support customisation of Office installations by editing the Office MSI package. The recommended (and more likely to be supported) method of modifying vendor packages is via transforms. You can create these in all major packaging tools or by using the MsiTrans.exe tool that ships with the SDK. You should also consider the use of transforms for customising your own packages. Using this technique you can have a single base package that can be deployed to a variety of clients, with customisation handled via one or more transforms.
Rule 13: Be careful with Installer GUIDS
The Installer uses GUIDs to uniquely identify applications, packages, features, etc. For example, the ProductID is the GUID used by the Installer to distinguish one application from another. It doesn’t matter if the package or application names for two different applications are different, if the IDs are the same, the Installer is likely to become confused and you will encounter problems with installation, repair and uninstall. You can use the same ProductID when a package is a newer build of an existing one, but you need to then have different PackageIDs to distinguish the application versions. If you want the packages to be upgrades of each other, then you need them to have the same UpgradeID. GUIDs should be all uppercase
Rule 14: Use Consistent Package Naming Conventions
The name of the MSI package itself doesn’t really matter as far as the Installer is concerned. As Rule 13 mentions, the Installer uses GUIDs to identify packages, etc. However, while the Installer doesn’t care about the original MSI name, once it registers that name for the product, it does care. Any small and/or minor update that is issued via an MSI must use the same base package name (the source location can be different depending upon source policy, but the base package name must be the same). Also, package naming is important from a user point of view. Consistent, user-friendly naming allows the user to identify a package's contents from the name alone. For example, the following convention can be useful in a corporate environement where there may be many in-house packages available to users: <Application Vendor>_<Product Name>_<Product Version>_<Department>.msi Following this, a repackaged version of Adobe Acrobat Reader v7.1 available to all users would be named: Adobe_AcrobatReader_71_ALL.msi
Rule 15: Do Not Try to Replace Protected System Files
Since the release of Windows 2000, Windows has shipped with Windows File Protection (WFP) , a mechanism for monitoring and restoring system files that have been renamed, deleted, etc. The Installer has no mechanism for by-passing WFP and if your package attempts to replace a protected file, the installation may not give the expected result. For the sake of application compatibility, the install does not fail if it is unable to update a WFP file. Instead, an entry is written to the application event log. However, it is important to note that the application may not be using the intended version of the file. Do not be tempted to work around this by using a custom action or other means. WFP will roll-back any changes you make. In any case, even if you managed to force your changes onto the system replacing protected files is simply unsupported by any means except Microsoft-approved methods. For example, by installing a Service Pack.
Rule 16: Follow Component Rules

Components are a very important part of the Installer technology. They are the means whereby the Installer manages the resources that make up your application. The SDK provides the following guidelines for creating components in your package:

  • Never create two components that install a resource under the same name and target location. If a resource must be duplicated in multiple components, change its name or target location in each component. This rule should be applied across applications, products, product versions, and companies.
  • Two components must not have the same key path file. This is a consequence of the previous rule. The key path value points to a particular file or folder belonging to the component that the installer uses to detect the component. If two components had the same key path file, the installer would be unable to distinguish which component is installed. Two components however may share a key path folder.
  • Do not create a version of a component that is incompatible with all previous versions of the component. This rule should be applied across applications, products, product versions, and companies.
  • Do not create components containing resources that will need to be installed into more than one directory on the user’s system. The installer installs all of the resources in a component into the same directory. It is not possible to install some resources into subdirectories.
  • Do not include more than one COM server per component. If a component contains a COM server, this must be the key path for the component.
  • Do not specify more than one file per component as a target for the Start menu or a Desktop shortcut.
Rule 17: Understand File Versioning Rules
The Installer has strict rules that it follows when determining whether to replace an existing file or not. File version, timestamp and language are all used to determine what to do in most cases. It is particularly important to understand what happens with unversioned files. Generally, these are treated as user data, and if any modification has taken place since the original install the Installer will not over-write. Refer to the SDK for full details of the versioning rules.
Rule 18: Improve Performance by Limiting System Restore During Setup
In a corporate environment where re-imaging or some other technique may be the preferred method for workstation recovery, and System Restore is never used, the additional time and disk space required to create the System Restore Points is essentially wasted. Turning it off for Installer activity will improve performance. You can turn off System Restore snapshots for installation using this per-machine policy setting: HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\InstallerLimitSystemRestoreCheckpointing = 1 This setting is affects only Installer-initiated restore activity and is available in Group Policy to aid its deployment to workstations. Note that System Restore is a very important feature of Windows and in most circumstances it is recommended that you do not switch it off, so this rule is only applicable for corporate scenarios where this feature is not used.
Rule 19: Avoid Using the SelfReg Table

Using the self-registering capabilities of certain DLLs is highly discouraged. Any activity performed by the self-registration (e.g. addition of registry entries) is out of the control of the Installer, so cannot be part of advertisement, repair and is not removed on uninstall. Instead you should have the Installer manage the data for you by using the appropriate tables in the MSI database. Some problems and limitations associated with self registration are:

  • The ability to use advertisement is reduced if class or extension server registration is performed within self-registration routines.
  • The installer automatically handles HKCR keys in the registry tables for both per-user and per-machine installations. DllRegisterServer routines currently do not support the notion of a per-user HKCR key.
  • If multiple users are using a self-registered application on the same computer, each user must install the application the first time they run it. Otherwise the installer cannot easily determine that the proper HKCU registry keys exist.
  • The DllRegisterServer can be denied access to network resources such as type libraries if a component is both specified as run-from-source and is listed in the SelfReg table. This can cause the installation of the component to fail to during an administrative installation.
  • Self-registering DLLs are more susceptible to coding errors because the new code required for DllRegisterServer is commonly different for each DLL. Instead use the registry tables in the database to take advantage of existing code provided by the installer.
  • Self-registering DLLs can sometimes link to auxiliary DLLs that are not present or are the wrong version. In contrast, the installer can register the DLLs using the registry tables with no dependency on the current state of the system.
Rule 20: Avoid Nested Installs

A nested installation action installs another Windows Installer package during a currently running installation. This is typically used to install some pre-requisite component(s) for the main application. Nested installs are deprecated and highly discouraged. Below are some of the limitations and problems associated with nested installs:

  • Concurrent installations cannot share components.
  • An administrative installation cannot also contain a concurrent installation.
  • Patching and upgrading may not work with concurrent installations. The installer may not properly cost a concurrent installation.
  • Integrated ProgressBars cannot be used with concurrent installations.
  • Resources that are to be advertised cannot be installed by the concurrent installation.
  • Nested installations live under the context of the parent product and do not appear in the Add or Remove Programs Control Panel applet. Therefore uninstall of the parent product is the only way to uninstall a nested install.
  • A package that performs a concurrent installation of an application should also uninstall the concurrent application when the parent product is uninstalled.

The recommendation would be to use the bootstrap executable wrapper to install the MSI packages one after another. Each individual MSI would therefore be serviceable and can be treated independently. The caveat to the bootstrap is that it can make deployment difficult. Group Policy deployment doesn’t have a concept of ordered dependencies in deployment of installation packages so if order is important you may not be as successful using this technique. This is especially problematic with low rights users since ZAP files do not allow for elevated installations.

Rule 21: Avoid Using Configuration Data You Don’t Own
As part of the initial design for the Installer, the consistency of installations was achieved via Microsoft taking ownership of the code for the install engine. This includes the location and format of all configuration data. This data is managed by the Installer and direct access by users or applications is discouraged; in fact some of the data is encoded to make it very difficult to manipulate manually. You should not try to peek directly into Windows Installer configuration information. Instead, use the Windows Installer API to get the information you need. Accessing the data this way ensures that your package or application will continue to work even if the underlying configuration data changes location or format.
Rule 22: Differentiate Between User and Application Data
All user registration data should be written to the HKEY_CURRENT_USER hive and application data to the HKEY_LOCAL_MACHINE hive. Also, your package should avoid over-writing user data during install, repair, etc. The user doesn’t want to have to re-configure their user-specific application settings after they repair the application.
Rule 23: Don’t Use Resources You are Installing
It is generally not a good practice to rely on the installation of certain non-critical resources. For example, a custom action that relies on the installation of a file that is part of an advertisable feature might fail when a user chooses to advertise the feature. Another typical scenario is a custom action sequenced ahead of InstallFinalize that uses methods exposed by an assembly that your setup is installing. Since assemblies are not committed to the GAC until towards the end of InstallFinalize, you can not use them until after that point.
Rule 24: Use Cabinet Files to Reduce Package Sizes
The Installer allows for packages to contain compressed and uncompressed source files. Compressing the files and storing them in a cabinet (.cab) file reduces the size of the package. The Installer allows the .cab file to be stored as a separate external file, or as a data stream in the MSI package itself. Note that for extremely large packages (i.e. with more than 32767 files), you must alter the schema to increase the number of files allowed. The steps to do this are documented in the SDK.
Rule 25: Follow Custom Action Rules

Custom actions allow for great flexibility in package installation, but are often the source of problems. The following are some simple rules to help get the best from your custom actions:

  • Do not initiate a System Restore snapshot from a custom action. Even if you want System Restore to operate during installs, you should not attempt to create a restore point yourself from a custom action. Such a snapshot will contain whatever partial changes that have taken place up to that point and restoring the system to this time would leave the system in an unknown state. At the least your application is likely to be non-functional, at worst the system could be unstable.
  • Log the Activity of Your Custom Actions. As is mentioned in several Rules, the Installer supports very detailed logging of its activities. However, the code inside your custom actions is hidden from the Installer, so it has no way to log what you're doing. Using either the Win32 API or the COM interface it is straightforward for your custom actions to log information about their activities, making it much easier to troubleshoot in the event of a problem.
  • Write a rollback custom action for every deferred custom action. Although custom actions that schedule system operations by inserting rows into database table are reversed by a rollback of the installation, custom actions that change the system directly, or that issue commands to other system services, cannot always be reversed by a rollback. You should write your own rollback custom action to take care of removing these changes.
  • Ensure that your impersonated custom action runs fine as a non-administrator account. This applies to all aspects of your package really, but it is easy to overlook in your own custom code. If you intend low-rights users to install your package then ensure that you test for this scenario.
  • Avoid using script custom actions for doing non-trivial setup actions. Scripted actions are easy to write, but are usually hard to maintain.
  • Think of ways to make your custom actions declarative. For example, use a custom tables to hold details of registry entries and files your custom action manipulates. Have your custom action read from these tables as it updates the system. This will give system administrators installing your package a better idea what your custom action is doing.
  • Do not show dialogue boxes from custom actions. Use MsiProcessMessage to send messages to the installer service that will decide on how to handle the message based on the UI level and other constraints. This is a much more scalable approach.
  • Be careful when calling Installer functions from a custom action. Calling certain functions - such as MsiUseFeature, MsiConfigureProduct, MsiApplyPatch, etc - will almost certainly lead to problems. Refer to the SDK for a full list of these functions.
  • Do not change the system state from an immediate custom action. You should not attempt to use an immediate execution custom action to change the system state, because every custom action that changes the state needs to have a corresponding rollback custom action to undo the system state change on an installation rollback. All rollback custom actions are also deferred custom actions and must precede the action they undo
Rule 26: Consider Storing User-specific Data in a File

Many applications store customisation data in the user’s registry on first use, and when the user is not logged on this data is stored in the user's .dat registry file on disk. This is all fairly standard, but a problem can arise if the application is removed when the user is not logged on - the data is inaccessible to the Installer and the application and so is effectively orphaned. This breaks the idea of having a clean uninstall. To work around this, you can store these setting in a file on disk, which will always be available during uninstall, or at least is very easy for the user to delete later themselves. This can be a simple text file, or, if you want to keep up with current trends, an XML file.

Rule 27: Consider Maintaining Setup in Text File Format
Many authoring tools such as the WiX toolkit now have underlying formats that permit building from text files. This makes viewing setup changes a lot easier and may be somewhat more intuitive for developers already used to dealing with version-controlled text files when writing application code. WiX is free and gives you the ability to stay very close to the Windows Installer technology without having to worry about every tiny detail (such as keeping foreign keys cased correctly).
Rule 28: Think about Localisation
What if your package is English and a user in China installs it onto a Chinese system? In order to anticipate and cope with such situations learn about Installer properties like ProductLAnguage, Template Summary information property, code pages of the database and summary information for the package. You should prepare for localization when authoring the original installation package. Design the layout of localised files such that different language versions can safely coexist when installed on the user’s computer. Organise files requiring localization into separate components and install these files into separate directories.
Rule 29: Follow the Assembly Rules

The Installer can install, remove and update Win32 and .NET assemblies, including side-by-side and private assemblies in Windows XP. To avoid common problems, follow these rules when using assemblies: General:

  • A component should contain no more than one assembly
  • All of the files in an assembly should be in a single component
  • Each component that contains an assembly should have an entry in the MsiAssembly table
  • The strong assembly cache name of each assembly should be authored into the MsiAssemblyName table
  • Use the Registry table instead of the Class table when you register COM Interop for an assembly
  • Assemblies that have the same strong name are the same assembly. When the same assembly is installed by different applications, the components that contain the assembly should use the same value for the ComponentId in their Component tables

Win32 Assemblies:

  • Do not use the manifest file or the catalogue file as the KeyPath in the Component table for the component containing the Win32 assembly
  • The KeyPath value in the Component table for a component that contains a Win32 policy assembly should be Null.
  • Add a row to the MsiAssemblyName table for each name and value pair that are listed in the <assemblyIdentity> section of the Win32 assembly's manifest

.NET Assemblies:

  • The KeyPath value in the Component table for a component that contains the assembly should not be Null
  • When you install an assembly used by the common language runtime to the global assembly cache, the value in the File_Application column of the MsiAssembly table must be Null
  • Add a row to the MsiAssemblyName table for each attribute of the assembly's strong name. All assemblies must have the Name, Version, and Culture attributes that are specified in the MsiAssemblyName table. A publicKeyToken attribute is required for a global assembly

[Author: Richard Macdonald]

This posting is provided "AS IS" with no warranties, and confers no rights.