Search code examples
c#registryregistrykey

C# Get BaseKey from RegistryKey


I have an open Registry Subkey, for example, HKEY_CURRENT_USER\SOFTWARE\Microsoft. How to get out of it the Base Registry Key or Registry Hive?

The RegistryKey.OpenBaseKey(RegistryHive, RegistryView) method does not have an overload to pass a RegistryKey or string to it.

I wrote the following code:

// OUR INPUT:
RegistryKey inputKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft");

string subKeyName = subkey.ToString();
string hiveName = subKeyName.Substring(0, subKeyName.IndexOf('\\'));

RegistryHive regHive;

switch (hiveName)
{
  case "HKEY_CLASSES_ROOT": regHive = RegistryHive.ClassesRoot; break;
  case "HKEY_CURRENT_USER": regHive = RegistryHive.CurrentUser; break;
  case "HKEY_LOCAL_MACHINE": regHive = RegistryHive.LocalMachine; break;
  case "HKEY_USERS": regHive = RegistryHive.Users; break;
  case "PerformanceData": regHive = RegistryHive.LocalMachine; break;
  case "CurrentConfig": regHive = RegistryHive.CurrentConfig; break;
  case "DynData": regHive = RegistryHive.DynData; break;
  default: throw new System.ArgumentOutOfRangeException();
}

// OUR TARGET:
RegistryKey baseKey = RegistryKey.OpenBaseKey(regHive, RegistryView.Default);

It works, but it seems to me that there should be a better solution.

Maybe you know another solution?


Solution

  • @TheGeneral, thanks for the link to source code. In the registry.cs, I found a method that does what I need. Unfortunately, it is private method and we need to rewrite it again in our project:

    Microsoft Solution:

    // Following function will parse a keyName and returns the basekey for it.
    // It will also store the subkey name in the out parameter.
    // If the keyName is not valid, we will throw ArgumentException.
    // The return value shouldn't be null. 
    //
    [System.Security.SecurityCritical]  // auto-generated
    private static RegistryKey GetBaseKeyFromKeyName(string keyName, out string subKeyName) {
         if( keyName == null) {
              throw new ArgumentNullException("keyName");
         }
    
         string basekeyName;
         int i = keyName.IndexOf('\\');
         if( i != -1) {
              basekeyName = keyName.Substring(0, i).ToUpper(System.Globalization.CultureInfo.InvariantCulture);
         }
         else {
              basekeyName = keyName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
         }   
         RegistryKey basekey = null;
    
         switch(basekeyName) {
      case "HKEY_CURRENT_USER": 
          basekey = Registry.CurrentUser;
          break;
      case "HKEY_LOCAL_MACHINE": 
          basekey = Registry.LocalMachine;
          break;
      case "HKEY_CLASSES_ROOT": 
          basekey = Registry.ClassesRoot;
          break;
      case "HKEY_USERS": 
          basekey = Registry.Users;
          break;
      case "HKEY_PERFORMANCE_DATA": 
          basekey = Registry.PerformanceData;
          break;
      case "HKEY_CURRENT_CONFIG": 
          basekey = Registry.CurrentConfig;
          break;
      case "HKEY_DYN_DATA": 
          basekey = RegistryKey.GetBaseKey(RegistryKey.HKEY_DYN_DATA);
          break;      
      default:
          throw new ArgumentException(Environment.GetResourceString("Arg_RegInvalidKeyName", "keyName"));
         }     
         if( i == -1 || i == keyName.Length) {
              subKeyName = string.Empty;
         }
         else {
              subKeyName = keyName.Substring(i + 1, keyName.Length - i - 1);
         }
         return basekey;
     }
    

    My Solution: I rewrote it as an extension methods:

    public static RegistryHive GetRegistryHive(this RegistryKey key)
    {
        if (key == null)
        {
            throw new System.ArgumentNullException(nameof(key));
        }
        int i = key.Name.IndexOf('\\');
        string basekeyName = (i != -1) ? key.Name.Substring(0, i) : key.Name;
        switch (basekeyName)
        {
            case "HKEY_CLASSES_ROOT": return RegistryHive.ClassesRoot;
            case "HKEY_CURRENT_USER": return RegistryHive.CurrentUser;
            case "HKEY_LOCAL_MACHINE": return RegistryHive.LocalMachine;
            case "HKEY_USERS": return RegistryHive.Users;
            case "HKEY_PERFORMANCE_DATA": return RegistryHive.LocalMachine;
            case "HKEY_CURRENT_CONFIG": return RegistryHive.CurrentConfig;
            case "HKEY_DYN_DATA": return RegistryHive.DynData;
            default: throw new System.ArgumentException(nameof(basekeyName));
        }
    }
    
    public static RegistryKey OpenBaseKey(this RegistryKey key)
    {
        return RegistryKey.OpenBaseKey(GetRegistryHive(key), key.View);
    }