views:

138

answers:

4

Is there a way to use visual studio's "add assembly reference dialog" (or something similar) in my own application? I need it for dynamic code generation and compilation.

This is not simply an OpenFileDialog, since it additionally looks into the GAC and so on, so it will be very complicated to do it on my own, I think.

If this is not possible, how can I get a list of all assemblies from the GAC?

+1  A: 

You dont want your app to be that slow, do you :P

Source is available for CR_QuickAddReference.

Ruben Bartelink
Slow like what? If the use opens the add reference dialog it is ok if he has to wait a few seconds.
codymanix
It's a generally accepted thing I've heard from hundreds of sources such as http://weblogs.asp.net/scottgu/archive/2009/10/29/add-reference-dialog-improvements-vs-2010-and-net-4-0-series.aspx. But the smiley is intended to acknowledge that you want similar functionality and that thats's a perfectly reasonable goal.
Ruben Bartelink
+2  A: 

There's an undocumented API which allows you to enumerate assemblies from the GAC.

Darin Dimitrov
A: 

Hi codymanix,

The following VS add in is exactly for you

http://visualstudiogallery.msdn.microsoft.com/en-us/36a6eb45-a7b1-47c3-9e85-09f0aef6e879

Muse VSExtensions
Unless I'm missing something, yours is just an add-in to VS and cannot be used programmatically.
Nelson
Starting to be a bit spammy here, Muse.
John Saunders
Hi,@ Nelson - Yes you a right Muse VSExtension is just an add-in and you can reflect this add in ;)@ John - Sorry if this post looks like a spam
Muse VSExtensions
I specifically looked through his posts and there were at least some non-spammy ones, otherwise I would have been harsher. :)
Nelson
+1  A: 

Hello,

The best way to get all assemblies from the GAC is to use Fusion

first approch: The following code snippet shows how to achieve your goal:

internal class GacApi
{
    [DllImport("fusion.dll")]
    internal static extern IntPtr CreateAssemblyCache(
    out IAssemblyCache ppAsmCache,
    int reserved);
}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")]
internal interface IAssemblyCache
{
    int Dummy1();
    [PreserveSig()]
    IntPtr QueryAssemblyInfo(int flags, [MarshalAs(UnmanagedType.LPWStr)] String assemblyName, ref ASSEMBLY_INFO  assemblyInfo); int Dummy2(); int Dummy3(); int Dummy4();
}

[StructLayout(LayoutKind.Sequential)]
internal struct ASSEMBLY_INFO
{
    public int      cbAssemblyInfo;
    public int      assemblyFlags;
    public long     assemblySizeInKB;
    [MarshalAs(UnmanagedType.LPWStr)]
    public String   currentAssemblyPath;
    public int      cchBuf;
}
class Program
{
    static void Main()
    {
        try
        {
            Console.WriteLine(QueryAssemblyInfo("System"));
        }
        catch(System.IO.FileNotFoundException e)
        {
            Console.WriteLine(e.Message);
        }
    }


    public static String QueryAssemblyInfo(String assemblyName)
    {
        ASSEMBLY_INFO  assembyInfo = new ASSEMBLY_INFO ();
        assembyInfo.cchBuf = 512;
        assembyInfo.currentAssemblyPath = new String('\0', assembyInfo.cchBuf) ;
        IAssemblyCache assemblyCache = null;
        IntPtr hr = GacApi.CreateAssemblyCache(out assemblyCache, 0);
        if (hr == IntPtr.Zero)
        {
            hr = assemblyCache.QueryAssemblyInfo(1, assemblyName, ref assembyInfo);
            if(hr != IntPtr.Zero)
            Marshal.ThrowExceptionForHR(hr.ToInt32());
        }
        else
        Marshal.ThrowExceptionForHR(hr.ToInt32());
        return assembyInfo.currentAssemblyPath;
    }
}

second approach: The GAC directory (%systemroot%\assembly for default installations) is a standard directory like any other directory and you should be able to loop through the directory, load the assemblies and retrieve type information of all types within the assembly.

Edit: The code for the easiest way:

            List<string> dirs = new List<string>() { 
                "GAC", "GAC_32", "GAC_64", "GAC_MSIL", 
                "NativeImages_v2.0.50727_32", 
                "NativeImages_v2.0.50727_64",
                "NativeImages_v4.0.50727_32", 
                "NativeImages_v4.0.50727_64" 
            };

        string baseDir = @"c:\windows\assembly";

        int i = 0;
        foreach (string dir in dirs)
            if (Directory.Exists(Path.Combine(baseDir, dir)))
                foreach (string assemblyDir in Directory.GetFiles(Path.Combine(baseDir, dir), "*.dll", SearchOption.AllDirectories))
                    Console.WriteLine(assemblyDir);

More information about Fusion.dll can be found at:

http://support.microsoft.com/kb/317540

@ codymanix - Let me know if you have other questions

Muse VSExtensions