Working with GAC from code
For some day ago I was working on testing an installer that did add some files to the GAC during installation. To ensure that the installer was working correct I needed some code that could check if some files did exist, add files and remove files from the GAC. I did need this for mainly 3 test cases; files already exist in GAC, files are installed correct and repair scenario when some files are deleted. I did find a good API wrapper on Junfena Zhana’s blog that did wrap the needed COM interactions. Based on this wrapper I did create a small class that did solve my problem.
Install assembly example
public static void InstallAssembly(string assemblyPath) { if (String.IsNullOrEmpty(assemblyPath)) { throw new ArgumentNullException("assemblyPath"); } AssemblyCache.InstallAssembly(assemblyPath, null, AssemblyCommitFlags.Force); } |
Check if assembly is installed example
public static bool AssemblyInstalled(string assemblyName) { if (String.IsNullOrEmpty(assemblyName)) { throw new ArgumentNullException("assemblyName"); } try { AssemblyCache.QueryAssemblyInfo(assemblyName); } catch (System.IO.FileNotFoundException) { return false; } return true; } |
Remove assemlby example
public static AssemblyCacheUninstallDisposition RemoveAssembly(string shortAssemblyName) { if (String.IsNullOrEmpty(shortAssemblyName)) { throw new ArgumentNullException("shortAssemblyName"); } string fullAssemblyName = GetFullAssemblyName(shortAssemblyName); if (String.IsNullOrEmpty(fullAssemblyName)) { throw new ArgumentException("Assembly=" + shortAssemblyName + ",not found in GAC"); } ClearRegKey(shortAssemblyName, Registry.CurrentUser, @"SoftwareMicrosoftInstallerAssembliesGlobal"); ClearRegKey(shortAssemblyName, Registry.ClassesRoot, @"InstallerAssembliesGlobal"); ClearRegKey(shortAssemblyName, Registry.LocalMachine, @"SoftwareClassesInstallerAssembliesGlobal"); AssemblyCacheUninstallDisposition uninstallDisposition; AssemblyCache.UninstallAssembly(fullAssemblyName, null, out uninstallDisposition); return uninstallDisposition; } |
GetFullAssemblyName. I don’t really like this implementation but it works.
private static string GetFullAssemblyName(string shortAssemblyName) { AssemblyCacheEnum assemblyCache = new AssemblyCacheEnum(null); while (true) { string assemblyFullName = assemblyCache.GetNextAssembly(); if (assemblyFullName == null) { break; } if (assemblyFullName.Split(',')[0].Contains(shortAssemblyName)) { return assemblyFullName; } } return String.Empty; } |
ClearRegKey
private static void ClearRegKey(string assemblyShortName, RegistryKey baseKey, string path) { RegistryKey key = baseKey.OpenSubKey(path, true); if (key != null) { string[] names = key.GetValueNames(); foreach (string name in names) { string[] words = name.Split(','); if (assemblyShortName == words[0]) { key.SetValue(name, "", RegistryValueKind.String); key.Close(); return; } } } } |