I build/maintain an IT support self-help app and recently had the need to include some registry key manipulation when users experience certain issues.I create the Reggie class to handle the general registry key manipulation:using System.Windows.Forms;using System;using Microsoft.Win32;namespace Reggie{    class Reggie : IDisposable    {        public RegistryKey BaseRegistryKey { get; set; } = Registry.LocalMachine;        public string SubKey { get; set; } = SOFTWARE\\;        public Reggie(RegistryKey root, string subkey)        {            BaseRegistryKey = root;            SubKey = subkey;        }        /// <summary>        /// Writes the given value to the         /// given key, which will be created        /// under whatever the SubKey property         /// is set to.         /// </summary>        /// <param name=keyName></param>        /// <param name=value></param>        /// <returns> true if the Write was successful, false otherwise. </returns>        public bool Write(string keyName, object value)        {            try            {                // Setting                RegistryKey rk = BaseRegistryKey;                // I have to use CreateSubKey                // (create or open if it already exists),                // because openSubKey opens a subKey as read-only                RegistryKey sk1 = rk.CreateSubKey(SubKey);                // Save the value                sk1.SetValue(keyName.ToUpper(), value);                return true;            }            catch (Exception ex)            {                MessageBox.Show(ex.Message);                return false;            }        }        /// <summary>        /// Returns the names of all subkeys below        /// the current SubKey, or null if there were        /// any errors.         /// </summary>        /// <returns></returns>        public string[] GetSubKeys()        {            RegistryKey rk = BaseRegistryKey;            try            {                RegistryKey sk1 = rk.OpenSubKey(SubKey);                return sk1.GetSubKeyNames();            }            catch (Exception ex)            {                MessageBox.Show(ex.Message);                return null;            }        }        /// <summary>        /// Returns the names of all values in        /// the current SubKey, or null if there        /// were any errors.         /// </summary>        /// <returns></returns>        public string[] GetValues()        {            RegistryKey rk = BaseRegistryKey;            try            {                RegistryKey sk1 = rk.OpenSubKey(SubKey);                return sk1.GetValueNames();            }            catch (Exception ex)            {                MessageBox.Show(ex.Message);                return null;            }        }        /// <summary>        /// Deletes the given value in whichever subkey        /// is currently set to the SubKey property.         /// </summary>        /// <param name=value></param>        /// <returns></returns>        public bool DeleteKeyValue(string value)        {            RegistryKey rk = BaseRegistryKey;            try            {                RegistryKey sk1 = rk.OpenSubKey(SubKey, true);                sk1.DeleteValue(value);                return true;            }            catch (Exception ex)            {                MessageBox.Show(ex.Message);                return false;            }        }        /// <summary>        /// Checks whether the current subkey exists by        /// attempting to open it with OpenSubKey().         /// If the resulting subkey is null, returns false.        /// </summary>        /// <returns></returns>        public bool Exists()        {            RegistryKey rk = BaseRegistryKey;            RegistryKey sk1 = rk.OpenSubKey(SubKey);            if (sk1 == null)            {                return false;            }            else            {                return true;            }        }        /// <summary>        /// Implementation of IDisposable.Dispose() to allow for 'using(Reggie){ ... }'        /// </summary>        public void Dispose()        {            // dispose of unmanaged resources.             Dispose(true);            // Suppress finalization.             GC.SuppressFinalize(this);        }        protected virtual void Dispose(bool disposing)        {        }    }}The function which is specific to my app is that I needed it to check all subkeys which exist under HKCU\Software\Microsoft\Office\15.0 and check whether they have any values saved in ...\appname\Resiliency\DisabledItems (this re-enables the disabled addin).I put together the DeleteSubKeys(Reggie, string) method:private static void DeleteSubKeys(Reggie reg, string subsubpath){    using (reg)    {        string subkeypath = reg.SubKey;        string[] strArrSubKeys = reg.GetSubKeys();        foreach (var key in strArrSubKeys)        {            // Reset the subkeypath ...            reg.SubKey = subkeypath;            // And then set it to the next key to search            reg.SubKey += key + subsubpath;            if (reg.Exists())            {                string[] strArrDisabledItemsValues = reg.GetValues();                foreach (var value in strArrDisabledItemsValues)                {                    reg.DeleteKeyValue(value);                }            }            else            {                continue;            }        }    }}Which will be called in the IT support app like so:public static void SelfHelpAppMethod()        {            // Set the registry root we are after             RegistryKey usersbase = Registry.Users;            // And the highest-level common subkey            string subkeypath = MyGlobals.Sid + @\Software\Microsoft\Office\15.0\;            // Set the next layer down. In this case, we want to delete all subkeys which exist underneath each application in Office/15.0 and also have Resiliency/disableditems values             string disabledaddinspath = @\Resiliency\DisabledItems;            // Creat a new Reg object            Reggie reg = new Reggie(usersbase, subkeypath);            // Delete the key values which are in the given path            DeleteSubKeys(reg, disabledaddinspath);        }You will notice that Reggie inherits IDisposable, and so has a Dispose() method. I think this is necessary for calling using (Reggie) { ... }, but I am not sure if I implemented it properly. Can anyone give me any insight into this based on what I have already done here?I am also hoping to get some feedback in terms of performance and whether or not I have put this together in a way which makes the most sense. Is there perhaps some other libraries I could add to this to make the code more readable?Any other feedback is more than welcome. For example, I'm not sure if the placement of try/catch blocks makes the most sense (please note that in live environment these catches will contain database updates rather than MessageBoxes). 
Searching subdirectories of a subdirectory for registry keys to delete
c#;performance;algorithm
I can't answer your main concerns but I'm not thrilled about the try/catch blocks.  All you seem to be doing in the catch is displaying the message and returning.  This marries your class to the UI, which means you can't make these calls in the background should you want to do that in the future.  My suggestion is just let your method throw but handled appropriately in the UI.I find the local copying of BaseRegistryKey to be unneeded:RegistryKey rk = BaseRegistryKey;RegistryKey sk1 = rk.OpenSubKey(SubKey);Why not simply use BaseRegistryKey such as:RegistryKey sk1 = BaseRegistryKey.OpenSubKey(SubKey);This would help simplify some of your coding.  For example Exists seems way too long.  It could be shorter:public bool Exists(){    return BaseRegistryKey.OpenSubKey(SubKey) != null;}Or a one-liner with C# 6.0 or better:public bool Exists() => BaseRegistryKey.OpenSubKey(SubKey) != null;Though I would think it should be a property rather than a method.  But you may also consider caching the exists state, which would alter my examples somewhat.Extending these thoughts to other methods, GetValues becomes:public string[] GetValues() => BaseRegistryKey.OpenSubKey(SubKey).GetValueNames();You may consider making BaseRegistryKey to be readonly if it doesn't change within the instance.  EDIT More about throw\catchAnother suggestion is to keep your throw\catch blocks but don't use MessageBox.  Instead you could have a public property called Exception, such as:public Exception Exception { get; private set; }public bool HasError => Exception != null;Then inside your current catch blocks you would capture that exception:catch (Exception ex){   Exception = ex;}You would then tie that back to your UI when the UI makes a call.  Instead of the UI using a try\catch it would be more like:reg.Write(keyName, value);if (reg.HasError){    MessageBox.Show(reg.Exception.Message);}