Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

A GAC Manager Utility and API

5.00/5 (20 votes)
30 Jul 2012CPOL5 min read 72K   6.8K  
Manage the Global Assembly Cache with this handy tool - or roll your own with the provided API!

Introduction  

With some of the work that I have been doing recently, I have had to spend lots of time inspecting and searching the GAC for certain assemblies. Some of the tools that I have found on the web to allow the GAC to be searched have been a little bit slow and basic for my liking, so to ease my development I have written a basic API to allow the GAC to be inspected, and a basic application that also aids in this task. 

Image 1

In this article, I will show how the GAC Manager tool works, how the API can be used, and the future of this project.

The GAC Manager Project 

As I am hoping to get feedback on this project and improve upon it over time, I have created a CodePlex page for the project, where you can get the very latest source code and binaries, as well as submit feature requests and bugs. The project is hosted at:

https://gacmanager.codeplex.com/

Please do visit the site for more information and to make feature requests! 

The GAC Manager Tool  

The GAC Manager Tool can be downloaded and installed from the links at the top of the article or the CodePlex site. When the tool is installed, it creates a shortcut in the start menu, in a folder named 'GAC Manager'. Run the tool and you get an interface like this:

Image 2 

I have tried to keep the interface as lean as possible. The toolbar allows you to perform the following commands:

Refresh

As you may expect, this command refreshes the list of assemblies installed in the GAC.

Install Assembly

This command allows you to install an assembly into the GAC. Note that the assembly must be strongly named!

Help

This command takes you straight to the CodePlex website, where you can find more information on the application or submit bugs or feature requests.

Assembly Details

This command shows the assembly details window for the currently selected assembly:

Image 3

Copy Display Name

This command copies the Display Name of the selected assembly to the clipboard. The Display Name is the qualified name of the assembly (including the version, public key etc) that can be used to load reflection details etc.

File Properties

The File Properties command simply invokes the shell 'File Properties' window for the selected assembly. 

Uninstall Assembly

Uninstalls the selected assembly from the GAC.

Open Containing Folder

The command opens the folder that the assembly is located in.

Search

The search box simply lets you filter the display of the assemblies by searching through them. The assemblies that are displayed will be any assembly with the search string in the name OR the public key token.

Image 4

The GAC Manager Api 

All of the functionality required to enumerate assemblies, install, uninstall etc is provided by the GAC Manager Api class library. This library currently uses the Fusion API to discover details of the assemblies in the GAC.  

Enumerating Assemblies 

We can use the AssemblyCacheEnumerator object to enumerate the assemblies in the global assembly cache. An example is below:

C#
//  Create an assembly enumerator.
var assemblyEnumerator = new AssemblyCacheEnumerator();
 
//  Get the first assembly.
var assemblyName = assemblyEnumerator.GetNextAssembly();
 
//  Start to loop through the assemblies.
while(assemblyName != null)
{
    //  The 'assemblyName' object is a COM interface, if we create an 
    //  AssemblyDescription from it, we will have access to more information.
    var assemblyDescription = new AssemblyDescription(assemblyName);
 
    //  Show the display name.
    System.Diagnostics.Trace.WriteLine("Display Name: " + assemblyDescription.DisplayName);
 
    //  Move to the next assembly.
    assemblyName = assemblyEnumerator.GetNextAssembly();
} 

As with many of the low-level API functions, the IAssemblyName object is what is actually passed around. This is a COM interface, and on its own not very useful. However, if we construct an 'AssemblyDescription' object from the interface, then we have access to a lot more information. Here's how the AssemblyDescription object looks:

Image 5 

An AssemblyDescription can be created from an IAssemblyName, or even from a plain string, as long as that string contains a valid assembly display name. 

Installing an Assembly 

The AssemblyCache class can be used to install an assembly.

C#
//  We'll need a path to the assembly to install.
var path = @"c:/MyAssembly.dll";
 
//  Install the assembly, without an install reference.
AssemblyCache.InstallAssembly(path, null, AssemblyCommitFlags.Default);

Easy! The second parameter is an Install Reference. This is an advanced topic and outside of the scope of this article, but it basically allows you to associate one assembly with another, or with an installed product. This means that if someone tries to uninstall that assembly later, it will not work unless the associated product is uninstalled at the same time.

Uninstalling an Assembly 

The AssemblyCache class can be used to uninstall an assembly.

C#
//  We'll need a display name of the assembly to uninstall.
var displayName = @"Apex, Version=1.4.0.0, Culture=neutral, PublicKeyToken=98d06957926c086d, processorArchitecture=MSIL";
 
//  When we try to uninstall an assembly, an uninstall disposition will be
//  set to indicate the success of the operation.
var uninstallDisposition = IASSEMBLYCACHE_UNINSTALL_DISPOSITION.Unknown;
 
//  Install the assembly, without an install reference.
try
{
    AssemblyCache.UninstallAssembly(displayName, null, out uninstallDisposition);
}
catch (Exception exception)
{
    //  We've failed to uninstall the assembly.
    throw new InvalidOperationException("Failed to uninstall the assembly.", exception);
}
 
//  Did we succeed?
if (uninstallDisposition == IASSEMBLYCACHE_UNINSTALL_DISPOSITION.IASSEMBLYCACHE_UNINSTALL_DISPOSITION_UNINSTALLED)
{
    //  Hooray!   
}

Uninstalling an assembly is more complicated. There are more things that can go wrong, an in fact the Uninstall Disposition enumeration is very helpful at letting us see what may have occurred. The second parameter for the UninstallAssembly function is an Install Reference - again as mentioned in the previous section this is a more complicated topic, but essentially it allows us to specify that the assembly is part of a larger collection of components.

Getting Advanced Fusion Properties 

The AssemblyDescription object has a property named 'FusionProperties'. This class holds more advanced properties that can only be acquired via the Fusion API. The reason that they are stored in their own object is that they are loaded lazily - Fusion Properties will only be discovered if they are needed, to ensure that the initial loading of lots of assemblies is speedy. Here's how they can be used: 

C#
//  Get the first assembly in the global assembly cache.
var someAssembly = new AssemblyDescription(new AssemblyCacheEnumerator().GetNextAssembly());
 
//  Show the install references.
foreach(var installReference in someAssembly.FusionProperties.InstallReferences)
    System.Diagnostics.Trace.WriteLine(installReference.Description);

Here you can see that we can access advanced details like the install references via the Fusion Properties.

Getting Advanced Reflection Properties 

There is another object available with more properties for an AssemblyDescription, this is the ReflecitonProperties object. Again, this is lazy loaded - and with very good reason, getting properties of an assembly via Reflection can be very slow - so by keeping these properties separate we make it very clear in code that we're using a property that may have a heavy overhead. Here's how we can get them:

C#
//  Get the first assembly in the global assembly cache.
var someAssembly = new AssemblyDescription(new AssemblyCacheEnumerator().GetNextAssembly());
 
//  Show the Runtime Version.
System.Diagnostics.Trace.WriteLine(someAssembly.ReflectionProperties.RuntimeVersio 

And that's all there is to it! 

The Future 

Currently this tool does what I need it to, but I'd love to improve upon it and make it a useful tool for the community. If you have any suggestions, then please do comment either on this article or the project homepage!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)