.NET Fusion
Home About Workshops Articles Writing Talks Books Contact

7. GAC References

Microsoft Installer understands .NET assemblies and the GAC. An MSI file can contain shared assemblies and when the MSI file is installed the shared assemblies will be installed into the GAC; when the MSI is uninstalled the assemblies will be removed from the GAC. Is this what you want? No, not necessarily. The reason is that a shared assembly will be used by one or more applications. The MSI files for those applications will install the same shared assembly into the GAC. If one of the applications is uninstalled it could remove the shared assembly from the GAC and so the remaining applications will not run.

Of course, this is not the case in practice because .NET has a mechanism to prevent this from happening. .NET handles this through GAC references. In simple terms, each time you install an assembly and indicate that reference counting is used, the reference count is incremented; each time you uninstall an assembly and indicate that reference counting is used, the reference count is decremented; when the reference count falls to zero, the assembly is removed from the GAC. gacutil uses the -r switch to handle reference counting and this switch can be combined with other switches. To install an assembly you use -ir:

gacutil -ir <assembly_file> <scheme> <id> <description>

Here, <scheme> determines how the assembly was installed and can be one of: UNINSTALL_KEY, which means that the assembly can be uninstalled through the control panel Add/Remove Programs and so uninstall information is stored in the registry; FILEPATH, which means that a separate process is used to uninstall the assembly; or OPAQUE, which indicates that you will uninstall the assembly in some other way. The <id> parameter depends on the <scheme> parameter and can contain the name of the registry key with uninstall information or the path to the uninstall application. <description> is whatever you choose.

7.1 Adding a GAC Reference

In this example, use the process, library and key file from the previous examples. Compile the library and install it with:

gacutil -ir lib.dll OPAQUE "myData" "my installer info"

This adds one reference for the assembly, the assembly could be installed for another application but to increment the reference count the <id> would have to be a different value to "myData". For example, add another reference with:

gacutil -ir lib.dll OPAQUE "myData2" "my installer info"

To list the references use the -lr switch, this can take a filter, for example:

C:\TestFolder>gacutil -lr lib

Microsoft (R) .NET Global Assembly Cache Utility. Version 1.1.4322
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

The Global Assembly Cache contains the following assemblies:
lib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=ede6789fb0b13219, Custom=null
SCHEME: <OPAQUE> ID: <myData> DESCRIPTION : <my installer info>
SCHEME: <OPAQUE> ID: <myData2> DESCRIPTION : <my installer info>

The cache of ngen files contains the following entries:

Number of items = 1

You can also confirm that the assembly is installed with references by selecting the assembly's properties in Windows Explorer:

.NET Version 3.0
The property page for assemblies in the GAC under .NET version 3.0/2.0 do not show the number of references. The only way to get this information is to use gacutil -lr.

To uninstall an assembly you have to provide the complete display name (or the short name if you feel confident that there are no other assemblies with the same short name), and the <scheme> and <id>. Bizarrely, you also have to include the <description> parameters that you used when installing the assembly:

gacutil -ur lib OPAQUE "myData" "my installer info"

(The description parameter is required but does not have to be the same as the string you used to add the assembly to the cache.) When you uninstall an assembly, read the output from gacutil carefully, you will see that it lists the references that have been removed, the pending references (ie references that have not been removed) and it will list the number of assemblies removed. The first time you call gacutil -ur Number of assemblies uninstalled will be zero because there will still be a reference on the assembly.

This will decrement the reference count and you can confirm this with Windows Explorer or gacutil. If you want to remove the assembly without using references you can use the -uf switch without the reference information (again, either the full name, or the short name):

gacutil -uf lib

There is another value for <scheme> and it is the value that will be used most often: WINDOWS_INSTALLER. This indicates that Windows Installer was used to install the assembly and therefore you can only uninstall the assembly using Windows Installer. If you try to uninstall the assembly with gacutil it will reject the WINDOWS_INSTALLER scheme.

I hope that you enjoy this tutorial and value the knowledge that you will gain from it. I am always pleased to hear from people who use this tutorial (contact me). If you find this tutorial useful then please also email your comments to mvpga@microsoft.com.

Errata

If you see an error on this page, please contact me and I will fix the problem.

Page Eight

This page is (c) 2007 Richard Grimes, all rights reserved