Checking for the presence of .Net Framework 2.0 SP1

Installware has a lot of built in support for checking for the presence of the various flavors of the .NET Framework.  In it’s current incarnation, 7.5, it doesn’t have anything for checking for the presence of Service Pack 1 of the .NET Framework 1.0.  It turned out to be pretty easy to add that check to my installer script.

A couple of years back Heath Stewart did a blog post about how to check for the presence of a .NET Service Pack.  You just look for the the value of “SP” in the registry key for the version of the .NET runtime that you want to check.  For .NET 2.0, that key would be labeled:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727

If you want to check against a language, you just check for the language id.  For example, English is ID 1033.  The key to check for the English version of the .NET 2.0 runtime would be.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727\1033

The SP is DWORD, so you will get back an integer result.  If the .NET runtime has been installed, it will have the SP value.   For the RTM release, it will be 0.

With InstallAware, I use the following syntax to check for .NET 2.0 SP1 and terminate the install if SP1 (or later) has not been installed.

Read Registry Key HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727\SP into CHECKSYSTEM
if Variable CHECKSYSTEM not Greater Than 0
MessageBox: $TITLE$ Setup Error, This product requires that the Microsoft .Net Framework 2.0 Service Pack 1 has been installed.$NEWLINE$$NEWLINE$Setup cannot continue.
Terminate Installation
end

For some reason, InstallAware does not have an “Less Than” operator, you have to do “not Greater Than”.  InstallAware is a leaky abstraction of the Windows Installer experience, I just shrug at those little oddities.

[Updated on 5/27/08]
I had a typo in the line that starts with “if Variable CHECKSYSTEM” where it should have been comparing against the value of 0, not 1.  My bad.

InstallAware doesn’t automatically remove assemblies from the GAC at uninstall time

I am updating the installer for one of our products to check for the presence of the SP1 version of the .NET 2.0 Framework, when I noticed something odd.  The assemblies that I was putting into the GAC were still there after an uninstall.  The guys at InstallAware seem to think that this is not a problem.  They refer to a topic in the MSDN, Removal of Assemblies from the Global Assembly Cache, which describes how the Windows Installer is not responsible for the removal of entries in the GAC:

The Windows Installer determines whether to allow the removal of a common language runtime assembly based upon a client list it keeps independently of the assembly. The Windows Installer keeps one pin bit to represent Windows Installer clients of the assembly. The installer pins the assembly for the first Windows Installer client and unpins it when the last Windows Installer client is removed. The assembly maintains a pin bit for every client of an assembly.

The Windows Installer is not directly responsible for the physical removal of common language runtime assemblies from the computer. The installer unpins the assembly when the last Windows Installer client is removed. If the Windows Installer is the last client of the assembly, the common language runtime provides the option to force a synchronous cleanup of the assembly. The cleanup process is atomic and there is no provision for a “rollback” at this point. All unpinning of common language runtime assemblies must occur after the user has had a chance to cancel the installation or removal.

That being said, the users want to uninstall everything.  Wise and InstallShield apparently do this.  With InstallShield, there is a property for the installed file called “Permanent”.  If it’s not set, it will be removed from the GAC if there are no other references to the assembly.

What InstallAware wants you to do is to explicitly remove the assembly during the uninstall portion of the install script.  They provide a command named “Remove Unpinned Assemblies” (it’s listed as “Remove Assemblies”).  This command will remove all unpinned assemblies that your installer had places into the GAC.  The code should look like this: 

  Apply Uninstall (get result into variable SUCCESS)
Remove Unpinned Assemblies

I’m still not sure if that will always work.  According to InstallAware, there is a bug in Windows Installer where sometimes the installer corrupts the Global Registry cache on .NET 2.0 assembles and there will always be a reference to unreferenced assembly.  The only work around is to delete the (Default) registry key for the assembly in the user and local machine hives.  This mess is documented here in the InstallAware support forum.

The work around sounds worse than the problem.  I’m not going to do a strafing run on the registry to deal with a Windows Installer bug.  Not when the only consequence is that a few assemblies (in my case, it’s only a few) get left in the GAC.  There are other ways of removing assemblies from the GAC.  The gacutil.exe utility can be used to check the reference count and to remove the assembly,  The “/lr” command line parameter will list the reference counts for each assembly.  The “/u” parameter will remove an assenbly from the GAC.  For the command-line shy, the free tool GacView provides an Explorer like view of the GAC and it’s easy to use to remove assemblies from the GAC.