Windows Installer, the Class table, and resiliency repair dialogs

A while back I wrote an article about Windows Installer and the resiliency feature. Anyone who has seen a small dialog appear saying "Configuring XXX....please wait" has seen resiliency in action. I wanted to talk in more detail about a specific type of problem I have seen that ends up inadvertantly triggering resiliency repairs at very random times.

According to the help documentation for Windows Installer, the Class table contains COM server-related information that must be generated as a part of the product advertisement. Each row may generate a set of registry keys and values. The associated ProgId information is included in this table.

In practice, what happens during setup is that for each entry in the Class table, a set of registry data is created under HKEY_CLASSES_ROOT\CLSID\{GUID} for the COM object in question. The {GUID} in this case is the value of the CLSID column of each row in the Class table of the MSI. This registry data allows the COM object to be instantiated on this machine by applications or custom script code later on.

There is also some additional data that advertises this COM object and associates it to any MSI that includes it in the Class table. If you look under the InprocServer32 subkey, you will see a REG_MULTI_SZ value that is also named InprocServer32. This collection of strings represents an encoded list of features that are associated with this COM object. Whenever an instance of this COM object is instantiated (with CoCreateInstance or WScript.CreateObject for example), Windows Installer recognizes that this COM object is advertised and proceeds to perform a feature health check for each of the features listed in the REG_MULTI_SZ value named InprocServer32 for this COM object. If this feature health check returns false for any reason, then you will see a small Windows Installer dialog and a resiliency repair, even if the information needed for this COM object is functioning perfectly fine.

I have run into this problem numerous times while debugging resiliency repairs that have popped up for internal users who installed daily builds of Visual Studio 2005. Using the debugging techniques in my previous blog article and also here have led me to components in Visual Studio that were being reported as broken. I had been meaning to write about this for a while, but it got put back in the forefront of my mind yesterday while I helped someone on the Visual Studio team figure out why they were seeing a repair dialog appear when they tried to build a setup/deployment project in the Visual Studio IDE. In this case, building a setup/deployment project was calling CoCreate on the MSM.Merge object exposed by mergemod.dll, and since this COM object was installed via the Class table of the Visual Studio MSI, it was advertised and a health check was triggered. The health check happened to fail due to a known bug in the VS MSI that is scheduled to be fixed soon.

This isn't that big of a deal for daily development work because there are experts within Microsoft that can look at the problem and also because the resiliency repair is exposing valid bugs (in several previous cases they were bugs in fusion related to new assembly attributes that were being treated as invalid because they were not recognized, see this blog item for more details if you're interested).

However, it becomes a big deal for end users who are trying to install and use shipped products and encountering repair dialogs for unknown reasons - and worse yet are being asked to insert a CD or browse to an inaccessible network location so that Windows Installer can access source files to try to repair them. In some products, especially large products such as Visual Studio, the feature that ends up being advertised in the registry by the Class table contains many components. A resiliency repair will be triggered even if some component that is completely unrelated to the functionality of the COM object being instantiated fails the Windows Installer health check.

Fortunately there is a way to avoid this issue for setup authors. I recommend using the standard MSI registry, file and component tables to install and register COM objects instead of using the Class table (and the companion ProgId table).