1
votes

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?

2
You could create an extension method for that, but I see no other option. When investigating the reference source code, it looks that the instance does not hold any property about the hive. The only place where this is actually used is inside the SafeRegistryHandle property - but it is not persisted. String comparisons are used allover. - ZorgoZ
Some of the mappings seem off, though. "HKEY_PERFORMANCE_DATA" = RegistryHive.PerformanceData, and I think the other strings should be "HKEY_CURRENT_CONFIG" and "HKEY_DYN_DATA" - Rufus L
@Rufus L, You are right, it was my carelessness. - DoubleDJ
@ZorgoZ, that's exactly what I did. I made a extension method fo RegistryKey using which I can get RegistryHive. And then I can use the existing method RegistryKey.OpenBaseKey(RegistryHive, RegistryView). - DoubleDJ

2 Answers

1
votes

You are essentially are on the right track and doing everything that can can be done.

The registry class is just a wrapper around the win32 API, there is no real magic that goes on here and works on string paths to the registry and hives.

Some more links :

As you have already noted, there are no easier way to achieve your desired goals

1
votes

@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);
}