This is a tool I use to figure out the binding closure of one or many assemblies. Per request, I post the source code here.

It is provided as it is. I did not do any significant testing.

Sample output:

F:\Code\closure>more 1.txt
system, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

F:\Code\closure>closure 1.txt
Initial assemblies are :
        1: system, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Binding closures are
        1: Microsoft.JScript, Version=8.0.1200.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        Assembly is in GAC.
        2: Microsoft.Vsa, Version=8.0.1200.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        Assembly is in GAC.
        3: mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        Assembly is in GAC.
        4: System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        Assembly is in GAC.
        5: System.Security, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
        Assembly is in GAC.
        6: System.Xml, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        Assembly is in GAC.

Here is the source code:

F:\Code\closure>more closure.cs

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting;
using System.Collections;
using System.Text;

class Closure
{
    public static void Main(String[] argv)
    {
        if (argv.Length != 1)
        {
            Console.WriteLine("Usage: Closure AsmList.txt");
            Console.WriteLine("AsmList.txt contains full display names of starting assemblies.");
            Console.WriteLine("One assemblies per line.");
            return;
        }

        try
        {
            ArrayList asms = new ArrayList(256);

            using (StreamReader sr = new StreamReader(argv[0]))
            {
                String line = null;

                while((line = sr.ReadLine()) != null)
                {
                    if (line != "") {
                        asms.Add(line);
                    }
                }
            }

            Closure closure = new Closure(asms);
            closure.Run();
            closure.ShowResult();
        }
        catch(Exception e)
        {
            Console.WriteLine("Exception: {0}", e.Message);
        }
    }

    public Closure(ArrayList asms)
    {
        names = new Queue(256);
        results = new Hashtable(null,CaseInsensitiveComparer.DefaultInvariant);
        failed = new ArrayList(256);

        initAsms = asms;

        foreach (String s in asms)
        {
            names.Enqueue(s);
        }
    }

    void Run()
    {
        Hashtable probed = new Hashtable(null,CaseInsensitiveComparer.DefaultInvariant);

        Assembly asm = null;
        while (names.Count != 0) {
            Object o = names.Dequeue();
            String s = o as String;
            if (s != null) {
                if (probed.Contains(s)) {
                    continue;
                }

                probed.Add(s, s);

                try {
                    asm = Assembly.Load(s);
                }
                catch(Exception e) {
                    if ((e is FileNotFoundException) || (e is FileLoadException)) {
                        failed.Add(s);
                        continue;
                    }
                    else {
                        throw;
                    }
                }

                String asmname = asm.FullName;
                if (!results.Contains(asmname)) {
                    results.Add(asmname, asm);
                }
                AssemblyName[] asmDepNames = asm.GetReferencedAssemblies();
                foreach(AssemblyName name in asmDepNames) {
                    asmname = name.FullName;
                    if (!probed.Contains(asmname)) {
                        names.Enqueue(asmname);
                    }
                }
            }
        }
    }

    void ShowResult()
    {
        initAsms.Sort();
        int i = 0;
        Console.WriteLine("Initial assemblies are :");
        foreach (Object o in initAsms) {
            String s = o as String;
            if (s != null) {
                i++;
                Console.WriteLine("\t{0}: {1}", i, s);
            }
        }

        Console.WriteLine("\nBinding closures are");
        ICollection keys = results.Keys;
        String[] sKeys = new String[keys.Count];
        keys.CopyTo(sKeys, 0);

        Array.Sort(sKeys, CaseInsensitiveComparer.DefaultInvariant);
        for(i=0; i< sKeys.Length;i++) {
            Console.WriteLine("\t{0}: {1}", i+1, sKeys[i]);
            Object o = results[sKeys[i]];
            Assembly asm = o as Assembly;
            if (asm != null) {
                if (asm.GlobalAssemblyCache) {
                    Console.WriteLine("\tAssembly is in GAC.");
                }
                else {
                    Console.WriteLine("\tAssembly is not in GAC.");
                }
            }
        }

        if (failed.Count != 0) {
            failed.Sort();
            Console.WriteLine("\nFollowing assemblies cannot be found :");
            i = 0;
            foreach (Object o in failed) {
                String s = o as String;
                if (s != null) {
                    i++;
                    Console.WriteLine("\t{0}: {1}", i, s);
                }
            }
        }
    }

    private ArrayList initAsms;
    private Queue   names;
    private Hashtable results;
    private ArrayList failed;
}