From ac41c04f673ba13187e174f2a4bc7b9bcc917ba8 Mon Sep 17 00:00:00 2001 From: Schmitti91 Date: Sun, 22 Oct 2023 12:18:42 +0200 Subject: [PATCH] mRemoteNG tools WindowsRegistry has been revised and the Windows Registry reading capabilities have been expanded in preparation for working with Registry Keys options. The "RegistryHive" enum was deleted because it is contained in "Microsoft.Win32". --- mRemoteNG/Tools/WindowsRegistry/IRegistry.cs | 34 +- .../Tools/WindowsRegistry/IRegistryRead.cs | 29 ++ .../Tools/WindowsRegistry/IRegistryWrite.cs | 21 + .../Tools/WindowsRegistry/RegistryHive.cs | 11 - .../Tools/WindowsRegistry/WindowsRegistry.cs | 388 +++++++++++++++++- .../WindowsRegistry/WindowsRegistryKey.cs | 213 ++++++++++ .../Tools/Registry/WindowsRegistryTests.cs | 167 +++++++- 7 files changed, 827 insertions(+), 36 deletions(-) create mode 100644 mRemoteNG/Tools/WindowsRegistry/IRegistryRead.cs create mode 100644 mRemoteNG/Tools/WindowsRegistry/IRegistryWrite.cs delete mode 100644 mRemoteNG/Tools/WindowsRegistry/RegistryHive.cs create mode 100644 mRemoteNG/Tools/WindowsRegistry/WindowsRegistryKey.cs diff --git a/mRemoteNG/Tools/WindowsRegistry/IRegistry.cs b/mRemoteNG/Tools/WindowsRegistry/IRegistry.cs index 32cff52a..a6e69061 100644 --- a/mRemoteNG/Tools/WindowsRegistry/IRegistry.cs +++ b/mRemoteNG/Tools/WindowsRegistry/IRegistry.cs @@ -1,8 +1,36 @@ -namespace mRemoteNG.Tools.WindowsRegistry +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Runtime.Versioning; + +namespace mRemoteNG.Tools.WindowsRegistry { + [SupportedOSPlatform("windows")] public interface IRegistry { - Optional GetKeyValue(RegistryHive hive, string keyPath, string propertyName); - string[] GetSubKeyNames(RegistryHive hive, string keyPath); + #region registry reader + string[] GetSubKeyNames(RegistryHive hive, string path); + + Optional GetPropertyValue(WindowsRegistryKey key); + Optional GetPropertyValue(RegistryHive hive, string path, string name); + + WindowsRegistryKey GetWindowsRegistryKey(RegistryHive hive, string path, string name); + WindowsRegistryKey GetWindowsRegistryKey(WindowsRegistryKey key); + + List GetRegistryEntries(RegistryHive hive, string path); + List GetRegistryEntryiesRecursive(RegistryHive hive, string path); + + #endregion + + #region registry writer + void SetRegistryValue(WindowsRegistryKey key); + void SetRegistryValue(RegistryHive hive, string path, string name, object value, RegistryValueKind valueKind); + + #endregion + + #region converter + RegistryHive ConvertStringToRegistryHive(string hiveString); + RegistryValueKind ConvertStringToRegistryValueKind(string valueType); + #endregion } } \ No newline at end of file diff --git a/mRemoteNG/Tools/WindowsRegistry/IRegistryRead.cs b/mRemoteNG/Tools/WindowsRegistry/IRegistryRead.cs new file mode 100644 index 00000000..8c6dfbc3 --- /dev/null +++ b/mRemoteNG/Tools/WindowsRegistry/IRegistryRead.cs @@ -0,0 +1,29 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Runtime.Versioning; + +namespace mRemoteNG.Tools.WindowsRegistry +{ + [SupportedOSPlatform("windows")] + public interface IRegistryRead + { + #region registry reader + string[] GetSubKeyNames(RegistryHive hive, string path); + + Optional GetPropertyValue(WindowsRegistryKey key); + Optional GetPropertyValue(RegistryHive hive, string path, string name); + + WindowsRegistryKey GetWindowsRegistryKey(RegistryHive hive, string path, string name); + WindowsRegistryKey GetWindowsRegistryKey(WindowsRegistryKey key); + + List GetRegistryEntries(RegistryHive hive, string path); + List GetRegistryEntryiesRecursive(RegistryHive hive, string path); + #endregion + + #region converter + RegistryHive ConvertStringToRegistryHive(string hiveString); + RegistryValueKind ConvertStringToRegistryValueKind(string valueType); + #endregion + } +} \ No newline at end of file diff --git a/mRemoteNG/Tools/WindowsRegistry/IRegistryWrite.cs b/mRemoteNG/Tools/WindowsRegistry/IRegistryWrite.cs new file mode 100644 index 00000000..0e46e449 --- /dev/null +++ b/mRemoteNG/Tools/WindowsRegistry/IRegistryWrite.cs @@ -0,0 +1,21 @@ +using Microsoft.Win32; +using System; +using System.Runtime.Versioning; + +namespace mRemoteNG.Tools.WindowsRegistry +{ + [SupportedOSPlatform("windows")] + public interface IRegistryWrite + { + #region registry writer + void SetRegistryValue(WindowsRegistryKey key); + void SetRegistryValue(RegistryHive hive, string path, string name, object value, RegistryValueKind valueKind); + + #endregion + + #region converter + RegistryHive ConvertStringToRegistryHive(string hiveString); + RegistryValueKind ConvertStringToRegistryValueKind(string valueType); + #endregion} + } +} \ No newline at end of file diff --git a/mRemoteNG/Tools/WindowsRegistry/RegistryHive.cs b/mRemoteNG/Tools/WindowsRegistry/RegistryHive.cs deleted file mode 100644 index 4663bf27..00000000 --- a/mRemoteNG/Tools/WindowsRegistry/RegistryHive.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace mRemoteNG.Tools.WindowsRegistry -{ - public enum RegistryHive - { - ClassesRoot, - CurrentConfig, - CurrentUser, - Users, - LocalMachine - } -} \ No newline at end of file diff --git a/mRemoteNG/Tools/WindowsRegistry/WindowsRegistry.cs b/mRemoteNG/Tools/WindowsRegistry/WindowsRegistry.cs index f121cd6d..53025028 100644 --- a/mRemoteNG/Tools/WindowsRegistry/WindowsRegistry.cs +++ b/mRemoteNG/Tools/WindowsRegistry/WindowsRegistry.cs @@ -1,39 +1,324 @@ -using System; +using Amazon.EC2.Model; +using Google.Protobuf.WellKnownTypes; +using Microsoft.Win32; +using MySqlX.XDevAPI.Common; +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; using System.Runtime.Versioning; -using Microsoft.Win32; +using System.Security; namespace mRemoteNG.Tools.WindowsRegistry { + /// + /// This class implements the IRegistryRead and IRegistryWrite interfaces and provides methods for interacting with the Windows Registry. + /// [SupportedOSPlatform("windows")] - public class WindowsRegistry : IRegistry + public class WindowsRegistry : IRegistry, IRegistryRead, IRegistryWrite { - public string[] GetSubKeyNames(RegistryHive hive, string keyPath) + #region public read + /// + /// Retrieves the names of subkeys under a specified registry key path. + /// + /// The RegistryHive where the subkeys are located. + /// The path to the registry key containing the subkeys. + /// An array of strings containing the names of subkeys, or an empty array if no subkeys are found. + public string[] GetSubKeyNames(RegistryHive hive, string path) { - keyPath.ThrowIfNull(nameof(keyPath)); + if (hive == 0) + throw new ArgumentException("Unknown or unsupported RegistryHive value.", nameof(hive)); + path.ThrowIfNull(nameof(path)); - using (var key = OpenSubKey(hive, keyPath)) + using (var key = OpenSubKey(hive, path)) { return key.Any() ? key.First().GetSubKeyNames() : new string[0]; } + } + + /// + /// Retrieves the value of a specific property within a Windows Registry key and returns it as an Optional. + /// + /// The WindowsRegistryKey containing information about the registry property. + /// An Optional containing the property value, or Optional.Empty if the value is not found. + public Optional GetPropertyValue(WindowsRegistryKey key) + { + if (!key.IsKeyReadable()) + throw new InvalidOperationException("The Windows Registry key is not ready for reading."); + + return GetPropertyValue(key.Hive, key.Path, key.Name); } - public Optional GetKeyValue(RegistryHive hive, string keyPath, string propertyName) + /// + /// Retrieves the value of a specific property within the Windows Registry and returns it as an Optional. + /// + /// The RegistryHive where the property is located. + /// The path to the registry key containing the property. + /// The name of the property to retrieve. + /// An Optional containing the property value, or Optional.Empty if the value is not found. + public Optional GetPropertyValue(RegistryHive hive, string path, string name) { - keyPath.ThrowIfNull(nameof(keyPath)); - propertyName.ThrowIfNull(nameof(propertyName)); + if (hive == 0) + throw new ArgumentException("Unknown or unsupported RegistryHive value.", nameof(hive)); + path.ThrowIfNull(nameof(path)); + name.ThrowIfNull(nameof(name)); - using (var key = OpenSubKey(hive, keyPath)) + using (var key = OpenSubKey(hive, path)) { if (!key.Any()) return Optional.Empty; - return key.First().GetValue(propertyName) as string; + return key.First().GetValue(name) as string; } } + /// + /// Retrieves a WindowsRegistryKey object for a specific registry hive, path, and value name. + /// + /// The RegistryHive of the key. + /// The path of the key. + /// The name of the value to retrieve. + /// A WindowsRegistryKey object representing the specified registry key and value. + public WindowsRegistryKey GetWindowsRegistryKey(RegistryHive hive, string path, string name) + { + WindowsRegistryKey key = new WindowsRegistryKey + { + Hive = hive, + Path = path, + Name = name + }; + + return GetWindowsRegistryKey(key); + } + + /// + /// Retrieves a WindowsRegistryKey object for a specific WindowsRegistryKey, populating its value and value kind. + /// + /// A WindowsRegistryKey object containing the hive, path, value name and more. + /// A WindowsRegistryKey object representing the specified registry key and value, with value and value kind populated. + public WindowsRegistryKey GetWindowsRegistryKey(WindowsRegistryKey key) + { + if (!key.IsKeyReadable()) + throw new InvalidOperationException("The Windows Registry key is not ready for reading."); + + using (RegistryKey baseKey = RegistryKey.OpenBaseKey(key.Hive, RegistryView.Default), subKey = baseKey.OpenSubKey(key.Path)) + { + if (subKey != null) + { + var value = subKey.GetValue(key.Name); + if (value != null) + key.Value = value.ToString(); + + RegistryValueKind ValueKind; + if (TestValueKindExists(subKey, key.Name, out ValueKind)) + key.ValueKind = ValueKind; + } + } + + return key; + } + + /// + /// Retrieves a list of registry entries (properties) and their values under a given key path. + /// + /// The RegistryHive of the key path. + /// The path of the key from which to retrieve values. + /// A list of WindowsRegistryKey objects, each representing a value within the specified registry key path. + public List GetRegistryEntries(RegistryHive hive, string path) + { + if (hive == 0) + throw new ArgumentException("Unknown or unsupported RegistryHive value.", nameof(hive)); + path.ThrowIfNull(nameof(path)); + + List list = new List(); + using (RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default), key = baseKey.OpenSubKey(path)) + { + if (key != null) + { + foreach (string valueName in key.GetValueNames()) + { + list.Add(new WindowsRegistryKey + { + Hive = hive, + Path = path, + Name = valueName, + Value = key.GetValue(valueName).ToString(), + ValueKind = key.GetValueKind(valueName) + } + ); + } + } + + } + return list; + } + + /// + /// Recursively retrieves registry entries under a given key path and its subkeys. + /// + /// The RegistryHive of the key path. + /// The path of the key from which to retrieve values. + /// A list of WindowsRegistryKey objects, each representing a value within the specified registry key path. + public List GetRegistryEntryiesRecursive(RegistryHive hive, string path) + { + if (hive == 0) + throw new ArgumentException("Unknown or unsupported RegistryHive value.", nameof(hive)); + path.ThrowIfNull(nameof(path)); + + List list = GetRegistryEntries(hive, path); + using (RegistryKey baseKey = RegistryKey.OpenBaseKey(hive, RegistryView.Default), key = baseKey.OpenSubKey(path)) + { + if (key != null) + { + foreach (string subPathName in key.GetSubKeyNames()) + { + string subKey = $"{path}\\{subPathName}"; + list.AddRange(GetRegistryEntryiesRecursive(hive, subKey)); + } + } + } + + return list; + } + #endregion + + #region public write methods + /// + /// Sets the value of a specific property within a registry key using individual parameters. + /// + /// The registry hive. + /// The path to the registry key containing the property. + /// The name of the property to set. + /// The value to set for the property. + /// The data type of the value to set. + public void SetRegistryValue(RegistryHive hive, string path, string name, object value, RegistryValueKind valueKind) + { + WindowsRegistryKey key = (new WindowsRegistryKey + { + Hive = hive, + Path = path, + Name = name, + Value = value.ToString(), + ValueKind = valueKind + }); + + CreateOrSetRegistryValue(key); + } + + /// + /// Sets the value of a specific property within a registry key using the provided WindowsRegistryKey object. + /// + /// The WindowsRegistryKey object containing information about the registry property. + public void SetRegistryValue(WindowsRegistryKey key) + { + CreateOrSetRegistryValue(key); + } + #endregion + + #region public methods + /// + /// Converts a string representation of a Registry Hive to the corresponding RegistryHive enum value. + /// + /// A string representation of a Registry Hive, not case-sensitive. + /// The RegistryHive enum value corresponding to the provided string representation. + /// Thrown if the provided string does not match a valid Registry Hive. + public RegistryHive ConvertStringToRegistryHive(string hiveString) + { + switch (hiveString.ToLower()) + { + // ClassesRoot + case "hkcr": + case "hkey_classes_root": + case "classesroot": + return RegistryHive.ClassesRoot; + + // CurrentUser + case "hkcu": + case "hkey_current_user": + case "currentuser": + return RegistryHive.CurrentUser; + + // LocalMachine + case "hklm": + case "hkey_local_machine": + case "localmachine": + return RegistryHive.LocalMachine; + + // Users + case "hku": + case "hkey_users": + case "users": + return RegistryHive.Users; + + // CurrentConfig + case "hkcc": + case "hkey_current_config": + case "currentconfig": + return RegistryHive.CurrentConfig; + + default: + throw new ArgumentException("Invalid registry hive string.", nameof(hiveString)); + } + } + + /// + /// Converts a string representation of a RegistryValueKind to the corresponding RegistryValueKind enum value. + /// + /// A string representation of a RegistryValueKind, not case-sensitive. + /// The RegistryValueKind enum value corresponding to the provided string representation. + /// Thrown if the provided string does not match a valid RegistryValueKind. + public RegistryValueKind ConvertStringToRegistryValueKind(string valueType) + { + switch (valueType.ToLower()) + { + // REG_SZ + case "string": + case "reg_sz": + return RegistryValueKind.String; + + // REG_DWORD + case "dword": + case "reg_dword": + return RegistryValueKind.DWord; + + // REG_BINARY + case "binary": + case "reg_binary": + return RegistryValueKind.Binary; + + // REG_QWORD + case "qword": + case "reg_qword": + return RegistryValueKind.QWord; + + // REG_MULTI_SZ + case "multistring": + case "reg_multi_sz": + return RegistryValueKind.MultiString; + + // REG_EXPAND_SZ + case "expandstring": + case "reg_expand_sz": + return RegistryValueKind.ExpandString; + + default: + throw new ArgumentException("Invalid RegistryValueKind string representation.", nameof(valueType)); + } + } + #endregion + + #region private methods + /// + /// Opens a subkey within the Windows Registry under the specified hive and key path. + /// + /// The Windows Registry hive where the subkey is located. + /// The path to the subkey to be opened. + /// + /// A disposable optional object containing the opened registry subkey if successful; + /// otherwise, it returns an empty optional object. + /// private DisposableOptional OpenSubKey(RegistryHive hive, string keyPath) { switch (hive) @@ -52,5 +337,86 @@ namespace mRemoteNG.Tools.WindowsRegistry throw new ArgumentOutOfRangeException(nameof(hive), hive, null); } } + + /// + /// Attempts to retrieve the value kind of a specific property within a registry subkey. + /// + /// The registry subkey from which to retrieve the value kind. + /// The name of the property for which to retrieve the value kind. + /// An output parameter that will contain the retrieved value kind, or RegistryValueKind.Unknown if the property or value kind is not found. + /// True if the operation is successful, otherwise false. + private bool TestValueKindExists(RegistryKey subKey, string valueName, out RegistryValueKind valueKind) + { + // Set a default value + valueKind = RegistryValueKind.Unknown; + try + { + valueKind = subKey.GetValueKind(valueName); + return true; + } + catch (Exception) + { + return false; + } + } + + /// + /// Creates or sets the value of a specific property within a registry key. + /// + /// The WindowsRegistryKey object containing information about the registry property. + /// Thrown when the Windows Registry key is not ready for writing. + /// Thrown when a security-related error occurs while accessing the registry. + /// Thrown when an I/O error occurs while accessing the registry. + /// Thrown when access to the registry is unauthorized. + /// Thrown for all other exceptions. + private void CreateOrSetRegistryValue(WindowsRegistryKey key) + { + try + { + if (!key.IsKeyWritable()) + throw new InvalidOperationException("The Windows Registry key is not ready for writing."); + + using (RegistryKey baseKey = RegistryKey.OpenBaseKey(key.Hive, RegistryView.Default), registryKey = baseKey.OpenSubKey(key.Path, true)) + { + if (registryKey == null) + { + // The specified subkey doesn't exist, so create it. + using (RegistryKey newKey = baseKey.CreateSubKey(key.Path)) + { + newKey.SetValue(key.Name, key.Value, key.ValueKind); + } + } + else + { + registryKey.SetValue(key.Name, key.Value, key.ValueKind); + } + } + } + catch (SecurityException ex) + { + // Handle or log SecurityException + // For example: log ex.Message + throw; + } + catch (IOException ex) + { + // Handle or log IOException + // For example: log ex.Message + throw; + } + catch (UnauthorizedAccessException ex) + { + // Handle or log UnauthorizedAccessException + // For example: log ex.Message + throw; + } + catch (Exception ex) + { + // For all other exceptions, log and rethrow + // For example: log ex.ToString() + throw; + } + } + #endregion } } \ No newline at end of file diff --git a/mRemoteNG/Tools/WindowsRegistry/WindowsRegistryKey.cs b/mRemoteNG/Tools/WindowsRegistry/WindowsRegistryKey.cs new file mode 100644 index 00000000..cc06b688 --- /dev/null +++ b/mRemoteNG/Tools/WindowsRegistry/WindowsRegistryKey.cs @@ -0,0 +1,213 @@ +using System; +using System.Runtime.Versioning; +using Microsoft.Win32; + + +namespace mRemoteNG.Tools.WindowsRegistry +{ + /// + /// This class provides a convenient way to work with Windows Registry keys + /// by encapsulating information about a registry key, including its path, + /// name, value, and registry hive/type. + /// + [SupportedOSPlatform("windows")] + public class WindowsRegistryKey + { + #region properties + + #region Property registryHive + public RegistryHive Hive + { + get { return _Hive; } + set + { + if (value == 0) + throw new ArgumentNullException("RegistryHive unknown."); + + _Hive = value; + } + } + private RegistryHive _Hive { get; set; } + #endregion + + #region Property path + public string Path + { + get { return _Path; } + set + { + value.ThrowIfNull(nameof(value)); + _Path = value; + } + } + private string _Path { get; set; } + #endregion + + #region Property name + public string Name + { + get { return _Name; } + set + { + value.ThrowIfNull(nameof(value)); + _Name = value; + } + } + private string _Name { get; set; } + #endregion + + #region Property valueKind + public RegistryValueKind ValueKind + { + get { return _ValueKind; } + set { + if (value == 0) + throw new ArgumentNullException("ValueKind unknown."); + + _ValueKind = value; + + // Check if Type is uninitialized (null) + if (_Type == null) + // Initialize Type if it's uninitialized + _Type = ConvertRegistryValueKindToType(value); + } + } + private RegistryValueKind _ValueKind; + #endregion + + #region Property type + public Type Type + { + get { return _Type; } + set { + _Type = value; + + // Check if ValueKind is uninitialized(0) + if (_ValueKind == 0) + // Initialize ValueKind if it's uninitialized + _ValueKind = ConvertTypeToRegistryValueKind(value); + } + } + private Type _Type; + #endregion + + public string Value { get; set; } + #endregion + + #region public methods + /// + /// Checks if the Windows Registry key is ready for reading by ensuring that the hive, + /// path, and name properties are set. + /// + /// True if the key is ready for reading, otherwise false. + public bool IsKeyReadable() { + return (IsHiveSet() && IsPathSet() && IsNameSet()); + } + + /// + /// Checks if the Windows Registry key is ready for a write operation. + /// The key is considered write-ready if none of the following conditions are met: + /// - The hive is set + /// - The registry value type is set + /// - The key path is set + /// - The value name is set + /// - The value data is set + /// + /// Returns true if the key is write-ready, otherwise false. + public bool IsKeyWritable() { + return (IsHiveSet() && IsValueKindSet() && IsPathSet() && IsNameSet()); + //return (IsHiveSet() && IsValueKindSet() && IsPathSet() && IsNameSet() && IsValueSet()); + } + #endregion + + #region private methods + /// + /// Converts a .NET data type to the corresponding RegistryValueKind. + /// + /// The .NET data type to convert. + /// The corresponding RegistryValueKind. + private RegistryValueKind ConvertTypeToRegistryValueKind(Type valueType) + { + switch (Type.GetTypeCode(valueType)) + { + case TypeCode.String: + return RegistryValueKind.String; + case TypeCode.Int32: + return RegistryValueKind.DWord; + case TypeCode.Int64: + return RegistryValueKind.QWord; + case TypeCode.Boolean: + return RegistryValueKind.DWord; + case TypeCode.Byte: + return RegistryValueKind.Binary; + /* + case TypeCode.Single: + return RegistryValueKind; + case TypeCode.Double: + return RegistryValueKind.String; + case TypeCode.DateTime: + return RegistryValueKind.String; // DateTime can be stored as a string or other types + case TypeCode.Char: + return RegistryValueKind.String; // Char can be stored as a string or other types + case TypeCode.Decimal: + return RegistryValueKind.String; // Decimal can be stored as a string or other types + */ + default: + return RegistryValueKind.String; // Default to String for unsupported types + } + } + + /// + /// Converts a RegistryValueKind enumeration value to its corresponding .NET Type. + /// + /// The RegistryValueKind value to be converted. + /// The .NET Type that corresponds to the given RegistryValueKind. + private Type ConvertRegistryValueKindToType(RegistryValueKind valueKind) + { + switch (valueKind) + { + case RegistryValueKind.String: + case RegistryValueKind.ExpandString: + return typeof(string); + case RegistryValueKind.DWord: + return typeof(int); + case RegistryValueKind.QWord: + return typeof(long); + case RegistryValueKind.Binary: + return typeof(byte[]); + case RegistryValueKind.MultiString: + return typeof(string[]); + case RegistryValueKind.Unknown: + default: + return typeof(object); + } + } + + private bool IsHiveSet() + { + return Hive != 0; + } + + private bool IsValueKindSet() + { + return ValueKind != 0; + } + + private bool IsPathSet() + { + return Path != null; ; + //return !string.IsNullOrEmpty(Path); + } + + private bool IsNameSet() + { + return Name != null; + } + + private bool IsValueSet() + { + return !string.IsNullOrEmpty(Value); + } + #endregion + } +} diff --git a/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs b/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs index 292b1b8a..67d7a6f5 100644 --- a/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs +++ b/mRemoteNGTests/Tools/Registry/WindowsRegistryTests.cs @@ -1,50 +1,195 @@ using System; +using System.Collections.Generic; using System.Linq; +using Microsoft.Win32; using mRemoteNG.Tools.WindowsRegistry; +using MySqlX.XDevAPI.Common; +using NSubstitute.ExceptionExtensions; using NUnit.Framework; namespace mRemoteNGTests.Tools.Registry { public class WindowsRegistryTests { - private WindowsRegistry _registry; + private IRegistry _registry; + private IRegistryRead _registryReader; + private IRegistryWrite _registryWriter; [SetUp] public void Setup() { _registry = new WindowsRegistry(); + _registryReader = new WindowsRegistry(); + _registryWriter = new WindowsRegistry(); } + #region GetSubKeyNames() tests [Test] public void CanGetSubkeyNames() { - var subKeyNames = _registry.GetSubKeyNames(RegistryHive.CurrentUser, "Software"); + var subKeyNames = _registryReader.GetSubKeyNames(RegistryHive.CurrentUser, "Software"); Assert.That(subKeyNames, Does.Contain("Microsoft")); } - [Test] public void GetSubkeyNamesThrowsIfGivenNullKeyPath() { - Assert.Throws(() => _registry.GetSubKeyNames(RegistryHive.CurrentUser, null)); + Assert.Throws(() => _registryReader.GetSubKeyNames(RegistryHive.CurrentUser, null)); } - [Test] - public void CanGetKeyValue() + public void GetSubkeyNamesThrowsIfGivenUnknownHive() { - var keyValue = _registry.GetKeyValue(RegistryHive.ClassesRoot, @".dll\PersistentHandler", ""); + Assert.Throws(() => _registryReader.GetSubKeyNames(new RegistryHive(), "Software")); + } + #endregion + + #region GetPropertyValue() tests + [Test] + public void CanGetPropertyValue() + { + var keyValue = _registryReader.GetPropertyValue(RegistryHive.ClassesRoot, @".dll\PersistentHandler", ""); Assert.That(keyValue.FirstOrDefault(), Is.EqualTo("{098f2470-bae0-11cd-b579-08002b30bfeb}")); } [Test] - public void GetKeyValueThrowsIfGivenNullKeyPath() + public void CanGetPropertyValueByRegistryKeyObject() { - Assert.Throws(() => _registry.GetKeyValue(RegistryHive.CurrentUser, null, "")); + WindowsRegistryKey key = new WindowsRegistryKey + { + Hive = RegistryHive.ClassesRoot, + Path = @".dll\PersistentHandler", + Name = "" + }; + + var keyValue = _registryReader.GetPropertyValue(key); + Assert.That(keyValue.FirstOrDefault(), Is.EqualTo("{098f2470-bae0-11cd-b579-08002b30bfeb}")); + } + [Test] + public void GetPropertyValueThrowsIfGivenNullKeyPath() + { + Assert.Throws(() => _registryReader.GetPropertyValue(RegistryHive.CurrentUser, null, "")); } [Test] - public void GetKeyValueThrowsIfGivenNullPropertyName() + public void GetPropertyValueThrowsIfGivenNullPropertyName() { - Assert.Throws(() => _registry.GetKeyValue(RegistryHive.CurrentUser, "", null)); + Assert.Throws(() => _registryReader.GetPropertyValue(RegistryHive.CurrentUser, "", null)); } + #endregion + + #region GetWindowsRegistryKey() tests + [Test] + public void CanGetWindowsRegistryKey() + { + WindowsRegistryKey keyValue = _registryReader.GetWindowsRegistryKey(RegistryHive.ClassesRoot, @".dll\PersistentHandler", ""); + Assert.That(keyValue.Value, Is.EqualTo("{098f2470-bae0-11cd-b579-08002b30bfeb}")); + } + + [Test] + public void CanGetWindowsRegistryKeyByObject() + { + WindowsRegistryKey key = new WindowsRegistryKey + { + Hive = RegistryHive.ClassesRoot, + Path = @".dll\PersistentHandler", + Name = "" + }; + + WindowsRegistryKey keyValue = _registryReader.GetWindowsRegistryKey(key); + Assert.That(keyValue.Value, Is.EqualTo("{098f2470-bae0-11cd-b579-08002b30bfeb}")); + } + + [Test] + public void CanGetWindowsRegistryKeyForKeyNotExists() + { + // No exception. Only null value + WindowsRegistryKey keyValue = _registryReader.GetWindowsRegistryKey(RegistryHive.LocalMachine, @"Software\Testabcdefg", "abcdefg"); + Assert.That(keyValue.Value, Is.EqualTo(null)); + } + + [Test] + public void GetWindowsRegistryThrowNotReadable() + { + WindowsRegistryKey key = new WindowsRegistryKey + { + Hive = RegistryHive.ClassesRoot, + }; + + Assert.Throws(() => _registryReader.GetWindowsRegistryKey(key)); + } + #endregion + + #region GetRegistryEntries() + Recurse tests + [Test] + public void CanGetRegistryEntries() + { + List keys = _registryReader.GetRegistryEntries(RegistryHive.LocalMachine, @"HARDWARE\DESCRIPTION\System\BIOS"); + Assert.That(keys.Count, Is.Not.EqualTo(0)); + } + + [Test] + public void CanGetRegistryEntriesRecurse() + { + List keys = _registryReader.GetRegistryEntryiesRecursive(RegistryHive.LocalMachine, @"SOFTWARE\Microsoft\Windows\Windows Search"); + Assert.That(keys.Count, Is.Not.EqualTo(0)); + } + #endregion + + #region new WindowsRegistryKey() tests + [Test] + public void IsWindowsRegistryKeyValid() + { + // Tests property rules of WindowsRegistryKey + WindowsRegistryKey key = new WindowsRegistryKey(); + + Assert.Multiple(() => + { + Assert.DoesNotThrow(() => key.Hive = RegistryHive.CurrentUser); + Assert.DoesNotThrow(() => key.ValueKind = RegistryValueKind.String); + Assert.DoesNotThrow(() => key.Path = "Software"); + Assert.DoesNotThrow(() => key.Name = "NotThereButOK"); + //Assert.DoesNotThrow(() => key.Value = "Equal", ""); + }); + + } + [Test] + public void WindowsRegistryKeyThrowHiveNullException() + { + WindowsRegistryKey key = new WindowsRegistryKey(); + Assert.Throws(() => key.Hive = 0, "Expected IsHiveValid to throw ArgumentNullException"); + } + + [Test] + public void WindowsRegistryKeyThrowValueKindNullException() + { + WindowsRegistryKey key = new WindowsRegistryKey(); + Assert.Throws(() => key.ValueKind = 0, "Expected IsValueKindValid to throw ArgumentNullException"); + } + [Test] + public void WindowsRegistryKeyThrowPathNullException() + { + WindowsRegistryKey key = new WindowsRegistryKey(); + Assert.Throws(() => key.Path = null, "Expected IsPathValid to throw ArgumentNullException"); + } + [Test] + public void WindowsRegistryKeyThrowNameNullException() + { + WindowsRegistryKey key = new WindowsRegistryKey(); + Assert.Throws(() => key.Name = null, "Expected IsNameValid to throw ArgumentNullException"); + } + #endregion + + #region SetRegistryValue() tests + [Test] + public void CanSetRegistryValue() + { + Assert.DoesNotThrow(() => _registryWriter.SetRegistryValue(RegistryHive.CurrentUser, @"SOFTWARE\mRemoteNGTest", "TestKey", "A value string", RegistryValueKind.String)); + } + + [Test] + public void SetRegistryValueThrowAccessDenied() + { + Assert.Throws(() => _registryWriter.SetRegistryValue(RegistryHive.LocalMachine, @"SOFTWARE\mRemoteNGTest", "TestKey", "A value string", RegistryValueKind.String)); + } + #endregion } }