Recently had a customer who had this requirement to find all .net assemblies which targets .net framework 1.1 on his machine. The reason for this was that they were de-commissioning all .net assemblies that targets .net 1.1.

So wrote a simple console application (EnumAssemblies.exe) for this customer, I thought why not share this with others just in case someone has a similar requirement. The console application takes the runtime version as a command line argument…

 

Few examples…

Usage

EnumAssemblies 1.1
EnumAssemblies 1.1.4322
EnumAssemblies 4.0

 

Sample output…

+============================================================================+
ADODB, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Runtime version: v1.1.4322
Location: C:\windows\assembly\GAC\ADODB\7.0.3300.0__b03f5f7f11d50a3a\ADODB.dll
+============================================================================+
+============================================================================+
Microsoft.VisualStudio.Debugger.Interop, Version=8.0.1.0, Culture=neutral, Publi
cKeyToken=b03f5f7f11d50a3a
Runtime version: v1.1.4322
Location: C:\windows\assembly\GAC\Microsoft.VisualStudio.Debugger.Interop\8.0.1.
0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Interop.dll
+============================================================================+
+============================================================================+
Microsoft.VisualStudio.Designer.Interfaces, Version=1.0.5000.0, Culture=neutral,
  PublicKeyToken=b03f5f7f11d50a3a
Runtime version: v1.1.4322
Location: C:\windows\assembly\GAC\Microsoft.VisualStudio.Designer.Interfaces\1.0
.5000.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Designer.Interfaces.dll
+============================================================================+
<snip>…

 

Logic

I’m using Fusion interfaces (http://msdn.microsoft.com/en-us/library/ms404523.aspx) for enumerating through GAC. .Net hasn’t provided a wrapper class over these interfaces and I’m too lazy to write one so who can help? Thanks to Junfeng Zhang's wrapper class over these interfaces, I was able to finish the whole implementation without much issues.

The next step was to load the assembly based on fully qualified name returned by fusion interfaces. When loading the assembly we should make sure that no code in the assembly is executed, all we need is the target runtime version. System.Reflection.Assembly is the class that represents an Assembly in .net and the function Assembly.ReflectionOnlyLoad is the function that loads an assembly into the reflection-only context, given its display name.

To get to the target runtime version, System.Reflection.Assembly provides a property: Assembly.ImageRuntimeVersion this gives us the targeted runtime version of an assembly.

So essentially the gist of this simple application rests in the following lines of code. Please note AssemblyCacheEnum is the wrapper class that Junfeng Zhang wrote.

AssemblyCacheEnum e = new AssemblyCacheEnum(null);
string s = e.GetNextAssembly();
while (s != null)
{
    Assembly a = Assembly.ReflectionOnlyLoad(s);
    if (a.ImageRuntimeVersion.Contains(FrameworkVer))
    {
        Console.WriteLine("+============================================================================+");
        Console.WriteLine(s + "\r\nRuntime version: " + a.ImageRuntimeVersion);
        Console.WriteLine("Location: {0}", a.Location);
        Console.WriteLine("+============================================================================+");
    }
    s = e.GetNextAssembly();
}

I've attached the project to this blog. Feel free to use it and obviously its not supported. Use it at your own risk. ;)