I’ve used a variety of installers over the past few years while doing Windows Client development. InstallShield, Nullsoft Installer, Caphyon’s Advanced Installer and last, but not least, Visual Studio Setup/Deployment projects.
They’re all intended to shield the developer from the innards of Windows Installer (or the custom installer technology). With varying degrees of success they make it easy to create the typical interaction between the user and the computer during an application install. Or at least that’s the idea.
Try as they might, these installers can’t entirely shield you from the underlying components, tables, properties, binary files and obscenely verbose MSI logs that are the world of the Windows Installer.
One such case has bedeviled a recent project as it relates to COM components. Whilst most of the codebase is managed code a few components (including a critical one) are still packaged as COM libraries. Registration-free COM, as I describe in an earlier post, relieves us of the perils of system-wide, centrally registered libraries that get installed and reinstalled by separate, not-necessarily cooperating applications.
However, one of the libraries is a 3rd party library that gets installed (and uninstalled) with several different applications. This is a problem because these applications are not always installed/uninstalled at the same time. They’re also versioned independently. In every case that I’ve seen installers will uninstall COM libraries when an application is uninstalled. This breaks every other application on the machine that depends on that COM library.
It turns out that the way to prevent application A from breaking application B when application A is uninstalled (and the shared COM library is uninstalled along with it) is to mark the COM library as a Shared, Reference Counted DLL.
No matter the installer this feature is controlled by a property taken directly from the guts of Windows Installer: msidbComponentAttributesSharedDllRefCount. This bit field determines whether or not Windows Installer will uninstall the DLL when the application is uninstalled.
The classical problem with using reference counting to track “liveness” (when a component is still in use) is the problem of circular references. If Components A and B depend on each other then they can never be removed entirely because their reference counts can’t be reduced to zero until they’re both zero. Fortunately this scenario hasn’t reared its head. When it does I’ll be sure to post.