Registry Hives...Parsing?

JaedenRuiner

Well-known member
Joined
Aug 13, 2007
Messages
340
Programming Experience
10+
Just wondering, in case it already exists somewhere but built into the .Net framework we have:

Microsoft.Win32.Registry Class
Microsoft.Win32.RegistryKey Class
Microsoft.Win32.RegistryHive Enumeration

As well as the.
My.Computer.Registry
.CurrentUser
.LocalMachine

Etcetera.

Now, If I were to say grab a registry key and execute the ToString() method I would get something like this:

HKEY_LOCAL_MACHINE\Software\MyCompany\MyApplication

The key is the Hive above. Now I can Do:
Microsoft.Win32.Registry.LocalMachine.OpenSubKey
or
My.Computer.Registry.LocalMachine.OpenSubKey

The Hive above is what determines the .LocalMachine, .CurrentUser, .ClassesRoot, etc, which is currently bound within the full string. I have not found any:
.Registry.OpenHive(HiveStringName)
command that would return the RegistryKey class that is pointed to by the LocalMachine or CurrentUser, and I am wondering if I must write the string parser for that myself which interprets the "HKEY_CURRENT_USER" into Registry.CurrentUser or if I'm just looking in the wrong places for it.

Thanks
 
You overlooked RegistryKey.OpenRemoteBaseKey Method that opens a registry key by a hive value, help explains how "remote" may actually be "local" for this.

System.Enum.Parse can parse a string into any enumeration value.
 
You overlooked RegistryKey.OpenRemoteBaseKey Method that opens a registry key by a hive value, help explains how "remote" may actually be "local" for this.
Thanks for pointing that out, but actually it isn't precisely what I wanted and I still have to do more. Frankly, I find Microsoft's division of Private and Friend classes most disheartening, since utilizing the reflector app, i've found quite a few things that are perfect for what i want, but they are declared Friend or Private:
EG: Registry.GetBaseKeyFromKeyName() which not only returns the Hive RegistryKey object, but parses out the sub key string for later use.
MS.Internal.IO.Zip.ZipArchive - which I will never understand why this is a Friend class, forcing .Net programmers to use the OPC ZipPackage class which addes the ConfigTypes file to every zip. Sometimes we programmers might just want to create/modify a Zip file, and I'd rather not use the DotNetZip open source library.
I definitely find it frustrating to find that there are methods and classes that do exactly what I want only to discover they are declared friend or private. *sigh*
System.Enum.Parse can parse a string into any enumeration value.
Well, as for this I have long ago written an extension:
VB.NET:
 <System.Runtime.CompilerServices.Extension()> _
   Public Function ToEnum(Of T)(ByVal Value As String) As T
      If GetType(T).IsEnum Then
         If Value.IndexOf("."c) > 0 Then
            Dim typ As Type = GetType(T)
            Dim l As Integer = Value.Split("."c).Length - 1
            If (l >= 1) AndAlso Value.Split("."c)(l - 1) = GetType(T).Name Then
               Value = Value.Split("."c)(l)
            End If
         End If
         Try
            Return CType([Enum].Parse(GetType(T), Value, True), T)
         Catch
            Return CType(CType(-1, Object), T)
         End Try
      Else : Throw New TypeLoadException("Type Parameter is not an Enumerated Type.")
      End If
   End Function

This works on any string, and is VERY helpful when going back and forth between strings and Enums, but again for this circumstance, I could recode the RegistryHive enum to directly String Match the HKEY_* strings, and correlate them to appropriate registry hive values, but even then the RegistryKey - GetBaseKey() which uses those enum values is declared friend so *grrr*
My Solution: (modified from reflector)
VB.NET:
   <System.Runtime.CompilerServices.Extension()> _
   Public Function OpenBaseKey(ByVal Registry As Microsoft.VisualBasic.MyServices.RegistryProxy, _
        ByVal FullKey As String, _
        Optional ByRef SubKey As String = "") As Microsoft.Win32.RegistryKey
      If FullKey.IsValid Then
         Dim index As Integer = -1
         Dim base As String = If(index.Assign(FullKey.IndexOf("\"c)) <> -1, _
               FullKey.Substring(0, index), _
               FullKey).ToUpper(Globalization.CultureInfo.InvariantCulture)
         Dim baseKey As Microsoft.Win32.RegistryKey = Nothing
         Select Case base
            Case "HKEY_CURRENT_USER" : baseKey = Registry.CurrentUser
            Case "HKEY_LOCAL_MACHINE" : baseKey = Registry.LocalMachine
            Case "HKEY_CLASSES_ROOT" : baseKey = Registry.ClassesRoot
            Case "HKEY_USERS" : baseKey = Registry.Users
            Case "HKEY_PERFORMANCE_DATA" : baseKey = Registry.PerformanceData
            Case "HKEY_CURRENT_CONFIG" : baseKey = Registry.CurrentConfig
            Case "HKEY_DYN_DATA" : baseKey = Registry.DynData
            Case Else
               Throw New ArgumentException("Invalid Registry Base Key Name {0}".FmtStr(FullKey))
         End Select
         If index.Between(1, FullKey.Length) Then SubKey = FullKey.Right(FullKey.Length - index)
         Return baseKey
      Else : Throw New ArgumentNullException("FullKey")
      End If
   End Function

this is limited to the My.Computer.Registry access as opposed to Microsoft.Win32.Registry access since the latter has no constructors and is non-inheritable, it is difficult (if not impossible) to extend. but that's only a minor setback.
 
Of course, if you don't have corresponding hive strings you either have to hardcode things, as your example, or manipulate the strings to fit in, you certainly can't rewrite the .Net library as it is. So if you have the registry exports "HKEY_LOCAL_MACHINE" etc you can always grab from first _ till first \ and remove any _ between, then you have a string valid for parsing into the RegistryHive enumeration. Some basic string manipulation is all it takes, I skip a few IndexOf calls in favour of Regex in this example:
VB.NET:
'path could be "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows" for example (copied from Regedit)

Function ParseRegistryPath(ByVal path As String) As RegistryKey    
    Dim pattern As String = "HKEY_(?<hive>\w+?)\\(?<keypath>.*)"
    Dim m As Match = Regex.Match(path, pattern)
    If Not m.Success Then
        Return Nothing
    End If
    Dim hivepart As String = m.Groups("hive").Value.Replace("_", String.Empty)
    Dim hive As RegistryHive = CType(System.Enum.Parse(GetType(RegistryHive), hivepart, True), RegistryHive)
    Return RegistryKey.OpenRemoteBaseKey(hive, String.Empty).OpenSubKey(m.Groups("keypath").Value)
End Function
 
I skip a few IndexOf calls in favour of Regex
Is Regex better in someway, like faster or something? I can see in this case how it is cleaner, easier to read and more efficient, but i sort of remember having heard regex is a memory or processor hog...I could be mistaken, *shrug*
 
Let me see if I have this right: you're writing software for Microsoft Windows to run inside of some version of the .Net Framework, and you're concerned that some module within that .Net Framework might be a memory or processor hog. That about right? :rolleyes:

Mind, I'm not saying I agree or disagree with MS' argument that the modern computing environment negates concerns over memory costs/performance or that CPU threading and speed negate concerns over processor bottlenecks (except that they are absolutely correct that you shouldn't trouble shoot bottlenecks until you have one and then use tools besides assumption to investigate and resolve them). However, I am pointing out that these are decisions, right or wrong, that Microsoft has made, so if you're going to take issue with those decisions, you should start with your choice of OS.

That said, yeah, the regular expression engine in .Net will hog whatever CPU it can get and consume a gob of memory while it's loaded, but it is also very fast. If you're goal in life is to ensure that your CPU wastes at least 50% or even 25% of it's computing power in idle processing, you should probably stay away from it.
 
Back
Top