tags:

views:

114

answers:

1

We are developing a MSI installer solution (based on VDPROJ, unfortunately) that will install an instance of our server application. The installer has all been designed to support the concept of installing multiple instances. This means we've written a small utility that takes a 'stub' MSI and then outputs a configured MSI with a unique Product Code, Product Name etc amongst other things. The Product Code is updated in both the Property table and Summary Information stream.

Everything seems to work fine on the install step. Our two test instances, AcmeCorp and ZurgCorp, are installed side-by-side just fine. Their Windows Services are all registered and function as expected.

However, we have encountered a very strange issue when it comes to uninstalling one of these instances. It doesn't matter which instance we uninstall first. But which ever one we choose, the uninstall will proceed very quickly - but so quickly that it actually misses out calling our .NET Installer subclass (tagged with RunInstaller and being called by the CustomAction).

The uninstall will be 'successful' and the MSI will be gone from Add/Remove Programs list. But the Windows Service remains behind because the MSI uninstaller never run our assembly to remove it!

Now if we go ahead and uninstall the second instance as well, this one will uninstall just fine including the Windows Service.

So what on earth is going on here?

It smells to me of some form of reference counting. But where? We've followed the book on this when it comes to making sure the Product Code's are different. Maybe there is something we are missing to do with Component Id's?

Thanks.

A: 

This is can be considered a hack, but it solves the issue. Of course there will be ramifications for MSI's that you intend to issue patches or upgrades for. But for our particular scenario this is not an issue because an upgrade will always involve uninstalling the server and then reinstalling it using the newer MSI.

Anyway, the workaround is this:-

Use Orca to look at your MSI. Go into the table called Component. In this table is a column called ComponentId. The values for all of these must be updated to have a new value (a fresh GUID). None of the other columns matter, the Component column which has a C__ prefix is only used internally by the MSI database. The critical one, as explained, is the ComponentId because this is the one that gets stored (albeit in some hashed/encrypted form) in the Windows Registry and is used by MSI to keep reference counters.

More detail on this ComponentId column is here: http://msdn.microsoft.com/en-us/library/aa368007%28VS.85%29.aspx

To automate this, I am going to improve our "Instance MSI Generator" utility to basically generate a new GUID for each record in the Component table.

NathanE
Bravo! :) ......
Vasiliy Borovyak