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;
      }
    }
  }
}
0.00 avg. rating (0% score) - 0 votes

About Peter Wibeck

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!

*