The GAC (aka Global Assembly Cache) is the central repository for assemblies
installed on a Windows machine. It provides a uniform, versioned and safe
access of assemblies by their strong assembly name. This article shows the
official way how to use this GAC from your application.
A few readers might have wondered, how do I access the GAC? The internal
structure of the GAC is not documented in the MSDN library but the filesystem
structure (e.g. C:\WINDOWS\assembly) seems simple enough to scan it. There is
however an undocumented COM API to access the GAC the (sort of) official way.
This is called the Fusion API because it is implemented by fusion.dll.
The basis of this work is the unofficial documentation of the GAC API in the
Microsoft KB article #317540
DOC: Global Assembly Cache (GAC) APIs Are Not Documented in the .NET Framework
Software Development Kit (SDK) Documentation. This article explains in
detail the use of the GAC API as implemented in fusion.dll. This DLL contains a
few API calls to create COM interfaces to various GAC related functionality
like adding or removing assemblies, enumerating installed assemblies and the
like. What we did here is to simply implement this API including the COM
interfaces in C# and adorn the code with the documentation snippets from the
mentioned KB article.
There is another way to use this API and this way depends on the implementation
of the GAC API inside the .NET framework. Obviously the .NET framework has full
access to the GAC for various reasons, even though this access is not
documented and flagged internal. The CodeProject article
Article "Undocumented Fusion" by
John Renaud describes nicely how to use this internal implementation
through reflection. This article is also insightful and describes some aspects
of the API (like the history for instance) that is left undocumented in the KB
article. We only give the naked implementation of the fusion.dll API and we
recommend Johns article as extra background reading and for examples.
Using the code
The first step should be to read the Microsoft KB article linked above. We added
almost all of this documentation as comments in our source for reference. This
should give you an idea what part of the API you actually need. The examples we
give here in this article all focus on the task of scanning the GAC for
installed assemblies. As a side note, you should be familiar with the COM
marshalling. See class
The following bits of code focus on how to scan the GAC. We start by creating
the enumeration interface.
IAssemblyEnum ae = AssemblyCache.CreateGACEnum();
This wraps the basic call to
CreateAssemblyEnum. On this interface
we can now enumerate
GetNextAssembly until the call return a COM
while (AssemblyCache.GetNextAssembly(ae, out an) == 0)
name = GetAssemblyName(an);
GetAssemblyName (not part of the downloadable sources)
IAssemblyName methods to retrieve all necessary
values to build a .NET-
AssemblyName instance. We will show them in
private AssemblyName GetAssemblyName(IAssemblyName nameRef)
AssemblyName name = new AssemblyName();
name.Name = AssemblyCache.GetName(nameRef);
name.Version = AssemblyCache.GetVersion(nameRef);
name.CultureInfo = AssemblyCache.GetCulture(nameRef);
GetName is an example how to obtain strings from the COM-API. If
you are not familiar with the COM marshaling of C#, you might wonder about the
use of the
StringBuilder. It is marshaled as a changeable char*.
ref string instead will lead to marshaling errors since
string is immutable.
public static String GetName(IAssemblyName name)
uint bufferSize = 255;
StringBuilder buffer = new StringBuilder((int) bufferSize);
name.GetName(ref bufferSize, buffer);
Another interesting case is the method
GetPublicKeyToken. It relies
uses a variant type for returning values:
int GetProperty(ASM_NAME PropertyId, IntPtr pvProperty, ref uint pcbProperty);
We use a
System.Runtime.InteropServices.IntPtr type to marshal this
variant. The downside is that we have to extract the desired values out of this
bulk of bits manually. The class
is of great service here:
public static byte GetPublicKey(IAssemblyName name)
uint bufferSize = 512;
IntPtr buffer = Marshal.AllocHGlobal((int) bufferSize);
name.GetProperty(ASM_NAME.ASM_NAME_PUBLIC_KEY, buffer, ref bufferSize);
byte result = new byte[bufferSize];
for (int i = 0; i < bufferSize; i++)
result[i] = Marshal.ReadByte(buffer, i);
This concludes the example. You find a few more wrapper methods in the
downloadable sources but for the most part you need to write the ones you need
along the lines sketched above.
This code is known to work with .NET 1.1 and 2.0. Please note that the DLL
fusion.dll is different in 1.1 and 2.0. So if you have both frameworks
installed, make sure to point the code to the right DLL. Otherwise most
API-calls will fail. The default implementation uses the one found in the
Version 1.0: submitted on 12th September 2004
No copyright reserved.
Greetings from a Smalltalk veteran.
I am exploring C# as the additional next programming language for our company and .NET as an additional strategic platform for our consulting offerings.
My personal aim is to transfer all the good properties of Smalltalk to .NET