Introduction
You may already - like me some time ago - have needed a possibility to read and to analyze an exported .reg file, in order to compare the given registry values or to import only few of the exported registry values.
In my case, I had to read a reg file of ca. 30 MB size, then compare all values with the existing registry values and change some of them - some kind of backup/restore solution for poor men ;-). I spent some time searching on the Internet for a ready-to-use solution, but all that I found was either another language (C++, VBS) or something not really efficient. So I decided to write my own DLL library to read and parse a reg file.
Background
I already used the .NET Regex
class in some projects and was really amazed at how smart the Regex
methods have been coded, working much quicker as for example the String
class methods. My read
function needs less than 5 seconds to read my 30 MB reg file on a standard 3Ghz PC (Windows 7).
The main class is the RegFileObject
class.
The raw content of the .reg file is stored in the private
field content
. The parsed registry values are stored in the RegValues
generic dictionary. The dictionary keys are the registry keys found in the .reg file. The dictionary values are again dictionaries with registry values names as dictionary keys and registry values data as dictionary values.
The RegValueObject
class diagram:
The program parses the reg file in two steps:
- Detecting all registry keys and the text content between each registry key pair and saving them as
Dictionary<string,string>
- Iterating through each found text content and parsing registry value names and values
The first parsing function is the NormalizeKeysDictionary
function. It "slices" the raw text content of the whole reg file using a search pattern ^[\t ]*\\[.+\\][\r\n]+
. It returns the output as a dictionary with found matches as dictionary keys and the whole raw text content between the current match end and next match begin as dictionary value.
private Dictionary<String, String> NormalizeKeysDictionary(String content)
{
string searchPattern = "^[\t ]*\\[.+\\][\r\n]+";
MatchCollection matches = Regex.Matches(content, searchPattern, RegexOptions.Multiline);
Int32 startIndex = 0;
Int32 lengthIndex = 0;
Dictionary<String, String> dictKeys = new Dictionary<string, string>();
foreach (Match match in matches)
{
try
{
String sKey = match.Value;
while (sKey.EndsWith("\r\n"))
{
sKey = sKey.Substring(0, sKey.Length - 2);
}
if (sKey.EndsWith("=")) sKey = sKey.Substring(0, sKey.Length - 1);
sKey = StripeBraces(sKey);
if (sKey == "@")
sKey = "";
else
sKey = StripeLeadingChars(sKey, "\"");
startIndex = match.Index + match.Length;
Match nextMatch = match.NextMatch();
lengthIndex = ((nextMatch.Success) ? nextMatch.Index : content.Length) - startIndex;
String sValue = content.Substring(startIndex, lengthIndex);
while (sValue.EndsWith("\r\n"))
{
sValue = sValue.Substring(0, sValue.Length - 2);
}
if (dictKeys.ContainsKey(sKey))
{
string tmpcontent = dictKeys[sKey];
StringBuilder tmpsb = new StringBuilder(tmpcontent);
if (!tmpcontent.EndsWith(Environment.NewLine)) tmpsb.AppendLine();
tmpsb.Append(sValue);
dictKeys[sKey] = tmpsb.ToString();
}
else
{
dictKeys.Add(sKey, sValue);
}
}
catch (Exception ex)
{
throw new Exception(String.Format
("Exception thrown on processing string {0}", match.Value), ex);
}
}
return dictKeys;
}
The second parsing function is the NormalizeValuesDictionary
function. It returns the output as a dictionary
with value names as dictionary keys
and the value content as dictionary value
.
private Dictionary<String, String> NormalizeValuesDictionary(String content)
{
string searchPattern = @"^[\t ]*("".+""|@)=(""[^""]*""|[^""]+)";
MatchCollection matches = Regex.Matches(content, searchPattern, RegexOptions.Multiline);
Dictionary<String, String> dictKeys = new Dictionary<string, string>();
foreach (Match match in matches)
{
try
{
String sKey = match.Groups[1].Value;
String sValue = match.Groups[2].Value;
while (sKey.EndsWith("\r\n"))
{
sKey = sKey.Substring(0, sKey.Length - 2);
}
if (sKey == "@")
sKey = "";
else
sKey = StripeLeadingChars(sKey, "\"");
while (sValue.EndsWith("\r\n"))
{
sValue = sValue.Substring(0, sValue.Length - 2);
}
if (dictKeys.ContainsKey(sKey))
{
string tmpcontent = dictKeys[sKey];
StringBuilder tmpsb = new StringBuilder(tmpcontent);
if (!tmpcontent.EndsWith(Environment.NewLine)) tmpsb.AppendLine();
tmpsb.Append(sValue);
dictKeys[sKey] = tmpsb.ToString();
}
else
{
dictKeys.Add(sKey, sValue);
}
}
catch (Exception ex)
{
throw new Exception(String.Format
("Exception thrown on processing string {0}", match.Value), ex);
}
}
return dictKeys;
}
Limitations
My .reg file parser doesn't support the remove directives (-[HKEY_LOCAL_MACHINE\SOFTWARE\TestSoftware]
), as it was not in focus of my project.
I have surely not discovered all issues on parsing f. ex. very "exotic" .reg files, but for my project, it was absolutely sufficient. The simplicity of the hereby presented parsing routines allow however to easily enhance the library by new functions.
Using the Code
The .reg file will be read on creating an instance of the RegFileObject
class:
RegFileObject regfile = new RegFileObject(@"C:\Temp\test.reg");
The searched registry value can be simply accessed by typing:
RegValueObject tempValue = regfile.RegValues
[@"HKEY_LOCAL_MACHINE\SOFTWARE\TestSoftware"]["TestValue"];
and the value data by querying the property Value
:
String tempData = tempValue.Value;
or directly:
RegFileObject regfile = new RegFileObject(@"C:\Temp\test.reg");
String tempData = regfile.RegValues
[@"HKEY_LOCAL_MACHINE\SOFTWARE\TestSoftware"]["TestValue"].Value;
The RegValues
dictionary can be very simply enumerated using the foreach
or for
statements.
History
- 8th November, 2010: Initial release
- 14th April, 2011: Fixed some typos
- 18th December, 2014: Fixed multiple empty lines bug (thanks to Jenda27)
- 3rd August, 2016: Fixed both mentioned issues (with the '
=
' character in the key name and double key names)