Is it possible to enumerate all installed versions of an assembly in GAC using C#? For example I have the assembly named "My.Assembly". The assembly may come in various versions ("1.0.0.0", "2.3.4.5", "0.1.2.4", ...) and may be compiled for various platforms (x86, x64, Any CPU).
Now I need a way to determine which of the versions/platforms are installed.
I'm aware that I could enumerate the directories in GAC but that seems wrong. There should be a better way to do this.
Background I have a launcher application in which the user selects a DLL. The launcher retrieves some information from the DLL (without loading it) and then has to start the correct managed C# application which handles the DLL. The DLL may be compiled for Win32 or x64 put exposes always the same (platform independent) interface. I use the LoadLibrary function to load the DLL in the C# applicaiton. The only problem is that the process has to be of matching format (x86 or x64). The C# application can and should be compiled for x86, x64 and Any CPU.
You can actually navigate to the GAC via explorer or the command line and view the contents of the folder. It's location is C:\Windows\assembly. When viewing via explorer the actual files are hidden and abstracted away, if you need to copy or extract specific versions of the dlls the command line is the way to go.
To install an assembly in the GAC, you must give the assembly a strong name. The name is a cryptographic hash-key, or signature. This strong name ensures correct component versioning.
Use the global assembly cache tool (gacutil.exe) to view the contents of the global assembly cache (GAC).
Using a managed wrapper for the Unmanaged Fusion API a was able to do exactly what I wanted to do:
class Program
{
static IEnumerable<AssemblyName> GetInstalledVersions(string name)
{
int result;
IAssemblyName assemblyName;
result = Utils.CreateAssemblyNameObject(out assemblyName, name, CreateAssemblyNameObjectFlags.CANOF_DEFAULT, IntPtr.Zero);
if ((result != 0) || (assemblyName == null))
throw new Exception("CreateAssemblyNameObject failed.");
IAssemblyEnum enumerator;
result = Utils.CreateAssemblyEnum(out enumerator, IntPtr.Zero, assemblyName, AssemblyCacheFlags.GAC, IntPtr.Zero);
if ((result != 0) || (enumerator == null))
throw new Exception("CreateAssemblyEnum failed.");
while ((enumerator.GetNextAssembly(IntPtr.Zero, out assemblyName, 0) == 0) && (assemblyName != null))
{
StringBuilder displayName = new StringBuilder(1024);
int displayNameLength = displayName.Capacity;
assemblyName.GetDisplayName(displayName, ref displayNameLength, (int)AssemblyNameDisplayFlags.ALL);
yield return new AssemblyName(displayName.ToString());
}
}
static void Main(string[] args)
{
foreach (AssemblyName assemblyName in GetInstalledVersions("System.Data"))
Console.WriteLine("{0} V{1}, {2}",
assemblyName.Name, assemblyName.Version.ToString(), assemblyName.ProcessorArchitecture);
}
}
Running the program above gives me the following output:
System.Data V2.0.0.0, Amd64
System.Data V2.0.0.0, X86
System.Data V4.0.0.0, Amd64
System.Data V4.0.0.0, X86
Thanks to Hans Passant who pointed me in the right direction!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With