* RegistryKeyTest.cs: Added large batch of tests.
authorGert Driesen <drieseng@users.sourceforge.net>
Tue, 15 Aug 2006 19:00:58 +0000 (19:00 -0000)
committerGert Driesen <drieseng@users.sourceforge.net>
Tue, 15 Aug 2006 19:00:58 +0000 (19:00 -0000)
* Win32ResultCode.cs: Added error code for attempting to perform an
operation on registry key that is marked for deletion.
* RegistryKey.cs: Keep writable state. Automatically flush changes to
disk when closing key (to match MS). Allow values to be set on root
keys. Throw UnauthorizedAccessException when attempting to set/delete
value or create/delete sub key on registry key that is openen
read-only. Fixed DecodeString to only strip trailing nullchars (as
documented).
* Win32RegistryApi.cs: For a key that is marked for deletion, return
null when attempting to get a value of that key (and no default value
was specified) or open a subkey. Throw an IOException when attempting
to perform the following operation on a key that is marked for
deletion:
        1) set value on key
        2) obtain SubKeyCount
        3) obtain ValueCount
        4) create a sub key
        5) obtain value names
and ignore deleting a value. Ignore flushing changes of a key and
closing a when the key is closed.
* UnixRegistryApi.cs: Maintain handler cache per directory instead of
caching registry keys. This allows both a single key to be in memory
in both read-only and read-write key configuration, while sharing the
KeyHandler. Use case-insensitive hashtable for mapping directory to
KeyHandler. Added support for keys that have been marked for deletion
by another operation (eg. DeleteSubKeyTree). Allow different file store
for machine-level and user-level hives (but have them use the same
file store, needs further discussion). Allow KeyHandler failure when
create directory, or saving values file to bubble up. Do not save
values file when key is marked for deletion. Encapsulate access to
values collection. When setting value with null name, use zero-length
name instead. Treat key name case-insensitive in DeleteKey to match
OpenSubKey.

svn path=/trunk/mcs/; revision=63781

mcs/class/corlib/Microsoft.Win32/ChangeLog
mcs/class/corlib/Microsoft.Win32/RegistryKey.cs
mcs/class/corlib/Microsoft.Win32/UnixRegistryApi.cs
mcs/class/corlib/Microsoft.Win32/Win32RegistryApi.cs
mcs/class/corlib/Microsoft.Win32/Win32ResultCode.cs
mcs/class/corlib/Test/Microsoft.Win32/ChangeLog
mcs/class/corlib/Test/Microsoft.Win32/RegistryKeyTest.cs

index b6f66167bc1cde7c7c657cd6f531787d81259ee4..efc6bf6b437fbdd47cd3548df998d490ca0b4a23 100644 (file)
@@ -1,3 +1,39 @@
+2006-08-14  Gert Driesen  <drieseng@users.sourceforge.net>
+
+       * Win32ResultCode.cs: Added error code for attempting to perform an
+       operation on registry key that is marked for deletion.
+       * RegistryKey.cs: Keep writable state. Automatically flush changes to
+       disk when closing key (to match MS). Allow values to be set on root
+       keys. Throw UnauthorizedAccessException when attempting to set/delete
+       value or create/delete sub key on registry key that is openen 
+       read-only. Fixed DecodeString to only strip trailing nullchars (as
+       documented).
+       * Win32RegistryApi.cs: For a key that is marked for deletion, return
+       null when attempting to get a value of that key (and no default value
+       was specified) or open a subkey. Throw an IOException when attempting
+       to perform the following operation on a key that is marked for
+       deletion:
+               1) set value on key
+               2) obtain SubKeyCount
+               3) obtain ValueCount
+               4) create a sub key
+               5) obtain value names
+       and ignore deleting a value. Ignore flushing changes of a key and
+       closing a when the key is closed.
+       * UnixRegistryApi.cs: Maintain handler cache per directory instead of
+       caching registry keys. This allows both a single key to be in memory
+       in both read-only and read-write key configuration, while sharing the
+       KeyHandler. Use case-insensitive hashtable for mapping directory to
+       KeyHandler. Added support for keys that have been marked for deletion
+       by another operation (eg. DeleteSubKeyTree). Allow different file store
+       for machine-level and user-level hives (but have them use the same
+       file store, needs further discussion). Allow KeyHandler failure when
+       create directory, or saving values file to bubble up. Do not save
+       values file when key is marked for deletion. Encapsulate access to
+       values collection. When setting value with null name, use zero-length
+       name instead. Treat key name case-insensitive in DeleteKey to match
+       OpenSubKey.
+
 2006-08-14  Miguel de Icaza  <miguel@novell.com>
 
        * RegistryValueKind.cs: Make this public in 2.0, and rename from
index 76ba31094eb741b4314f2da09ec9651b2fb5b678..d40dfbe6a1eeb8b9dfad2e27aa746f79c668eef3 100644 (file)
@@ -4,8 +4,8 @@
 // Author:
 //   Miguel de Icaza (miguel@ximian.com)
 //   Erik LeBel (eriklebel@yahoo.ca)
+//   Gert Driesen (drieseng@users.sourceforge.net)
 //
-
 //
 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
 //
@@ -50,12 +50,17 @@ namespace Microsoft.Win32
                //
                internal object Data;
                
-               string qname;   // the fully qualified registry key name
-               bool isRoot;    // is the an instance of a root key?
+               readonly string qname;  // the fully qualified registry key name
+               readonly bool isRoot;   // is the an instance of a root key?
+               readonly bool isWritable;       // is the key openen in writable mode
 
                internal bool IsRoot {
                        get { return isRoot; }
                }
+
+               internal bool IsWritable {
+                       get { return isWritable; }
+               }
                
                static readonly IRegistryApi RegistryApi;
 
@@ -75,16 +80,18 @@ namespace Microsoft.Win32
                        Data = hiveId;
                        qname = keyName;
                        isRoot = true;
+                       isWritable = true; // always consider root writable
                }
                
                /// <summary>
                ///     Construct an instance of a registry key entry.
                /// </summary>
-               internal RegistryKey (object data, string keyName)
+               internal RegistryKey (object data, string keyName, bool writable)
                {
                        Data = data;
                        qname = keyName;
                        isRoot = false;
+                       isWritable = writable;
                }
 
                #region PublicAPI
@@ -95,8 +102,8 @@ namespace Microsoft.Win32
                /// </summary>
                void IDisposable.Dispose ()
                {
-                       Close ();
                        GC.SuppressFinalize (this);
+                       Close ();
                }
 
                
@@ -128,11 +135,13 @@ namespace Microsoft.Win32
                
                
                /// <summary>
-               ///     Close the current registry key. This may not 
-               ///     flush the state of the registry right away.
+               ///     Close the current registry key and flushes the state of the registry
+               /// right away.
                /// </summary>
                public void Close()
                {
+                       Flush ();
+
                        if (isRoot)
                                return;
                        
@@ -171,13 +180,13 @@ namespace Microsoft.Win32
                public void SetValue (string name, object value)
                {
                        AssertKeyStillValid ();
-                       
+
                        if (value == null)
-                               throw new ArgumentNullException ();
+                               throw new ArgumentNullException ("value");
+
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
 
-                       if (isRoot)
-                               throw new UnauthorizedAccessException ();
-                       
                        RegistryApi.SetValue (this, name, value);
                }
 
@@ -189,13 +198,13 @@ namespace Microsoft.Win32
                        if (value == null)
                                throw new ArgumentNullException ();
 
-                       if (isRoot)
-                               throw new UnauthorizedAccessException ();
-                       
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
                        RegistryApi.SetValue (this, name, value, valueKind);
                }
 #endif
-       
+
                /// <summary>
                ///     Open the sub key specified, for read access.
                /// </summary>
@@ -247,6 +256,9 @@ namespace Microsoft.Win32
                        AssertKeyNameNotNull (subkey);
                        if (subkey.Length > 255)
                                throw new ArgumentException ("keyName length is larger than 255 characters", subkey);
+
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
                        return RegistryApi.CreateSubKey (this, subkey);
                }
                
@@ -268,16 +280,21 @@ namespace Microsoft.Win32
                        AssertKeyStillValid ();
                        AssertKeyNameNotNull (subkey);
 
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
                        RegistryKey child = OpenSubKey (subkey);
                        
                        if (child == null) {
                                if (throwOnMissingSubKey)
-                                       throw new ArgumentException ("key missing: " + subkey, "subkey");
+                                       throw new ArgumentException ("Cannot delete a subkey tree"
+                                               + " because the subkey does not exist.");
                                return;
                        }
 
                        if (child.SubKeyCount > 0){
-                               throw new InvalidOperationException ("key " + subkey + " has sub keys");
+                               throw new InvalidOperationException ("Registry key has subkeys"
+                                       + " and recursive removes are not supported by this method.");
                        }
                        
                        child.Close ();
@@ -300,7 +317,8 @@ namespace Microsoft.Win32
                        
                        RegistryKey child = OpenSubKey (keyName, true);
                        if (child == null)
-                               throw new ArgumentException ("key " + keyName + " at " + Name);
+                               throw new ArgumentException ("Cannot delete a subkey tree"
+                                       + " because the subkey does not exist.");
 
                        child.DeleteChildKeysAndValues ();
                        child.Close ();
@@ -325,6 +343,9 @@ namespace Microsoft.Win32
                        AssertKeyStillValid ();
                        AssertKeyNameNotNull (value);
 
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
                        RegistryApi.DeleteValue (this, value, shouldThrowWhenKeyMissing);
                }
                
@@ -423,10 +444,17 @@ namespace Microsoft.Win32
                {
                        string stringRep = Encoding.Unicode.GetString (data);
                        int idx = stringRep.IndexOf ('\0');
-                       if (idx >= 0)
-                               stringRep = stringRep.Substring (0, idx);
+                       if (idx != -1)
+                               stringRep = stringRep.TrimEnd ('\0');
                        return stringRep;
                }
+
+               static internal IOException CreateMarkedForDeletionException ()
+               {
+                       throw new IOException ("Illegal operation attempted on a"
+                               + " registry key that has been marked for deletion.");
+               }
+
        }
 }
 
index ac03de20eb854de0f644e78c086cd118885caf0c..7b0f364c48cba57e5c3c258262d33e97042e0727 100644 (file)
@@ -1,21 +1,20 @@
 //
-// Microsoft.Win32/IRegistryApi.cs
+// Microsoft.Win32/UnixRegistryApi.cs
 //
 // Authors:
 //     Miguel de Icaza (miguel@gnome.org)
+//     Gert Driesen (drieseng@users.sourceforge.net)
 //
 // (C) 2005, 2006 Novell, Inc (http://www.novell.com)
 // 
 // MISSING:
-//   Someone could the same subkey twice: once read/write once readonly,
-//   currently since we use a unique hash based on the file name, we are unable
-//   to have two versions of the same key and hence unable to throw an exception
-//   if the user tries to write to a read-only key.
-//
-//   It would also be useful if we do case-insensitive expansion of variables,
+//   It would be useful if we do case-insensitive expansion of variables,
 //   the registry is very windows specific, so we probably should default to
 //   those semantics in expanding environment variables, for example %path%
 //
+//   We should use an ordered collection for storing the values (instead of
+//   a Hashtable).
+//
 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
@@ -84,30 +83,31 @@ namespace Microsoft.Win32 {
                                        }
                                } else {
                                        sb.Append (value [i]);
-                               }               
+                               }
                        }
                        return sb.ToString ();
                }
        }
-       class KeyHandler {
+
+       class KeyHandler
+       {
                static Hashtable key_to_handler = new Hashtable ();
-               static Hashtable dir_to_key = new Hashtable ();
+               static Hashtable dir_to_handler = new Hashtable (
+                       new CaseInsensitiveHashCodeProvider (), new CaseInsensitiveComparer ());
+               /*
+                const string MACHINE_STORE_VAR = "MONO_REGISTRY_MACHINE";
+               */
+
                public string Dir;
-               public IntPtr Handle;
 
-               public Hashtable values;
+               Hashtable values;
                string file;
                bool dirty;
-               bool valid = true;
                
                KeyHandler (RegistryKey rkey, string basedir)
                {
                        if (!Directory.Exists (basedir)){
-                               try {
-                                       Directory.CreateDirectory (basedir);
-                               } catch (Exception e){
-                                       Console.Error.WriteLine ("KeyHandler error while creating directory {0}:\n{1}", basedir, e);
-                               }
+                               Directory.CreateDirectory (basedir);
                        }
                        Dir = basedir;
                        file = Path.Combine (Dir, "values.xml");
@@ -184,35 +184,39 @@ namespace Microsoft.Win32 {
                        }
                }
                
-               public RegistryKey Ensure (RegistryKey rkey, string extra)
+               public RegistryKey Ensure (RegistryKey rkey, string extra, bool writable)
                {
                        lock (typeof (KeyHandler)){
                                string f = Path.Combine (Dir, extra);
-                               if (dir_to_key.Contains (f))
-                                       return (RegistryKey) dir_to_key [f];
-
-                               KeyHandler kh = new KeyHandler (rkey, f);
-                               RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
+                               KeyHandler kh = (KeyHandler) dir_to_handler [f];
+                               if (kh == null)
+                                       kh = new KeyHandler (rkey, f);
+                               RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra), writable);
                                key_to_handler [rk] = kh;
-                               dir_to_key [f] = rk;
+                               dir_to_handler [f] = kh;
                                return rk;
                        }
                }
 
-               public RegistryKey Probe (RegistryKey rkey, string extra, bool write)
+               public RegistryKey Probe (RegistryKey rkey, string extra, bool writable)
                {
+                       RegistryKey rk = null;
+
                        lock (typeof (KeyHandler)){
                                string f = Path.Combine (Dir, extra);
-                               if (dir_to_key.Contains (f))
-                                       return (RegistryKey) dir_to_key [f];
-                               if (Directory.Exists (f)){
-                                       KeyHandler kh = new KeyHandler (rkey, f);
-                                       RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
-                                       dir_to_key [f] = rk;
+                               KeyHandler kh = (KeyHandler) dir_to_handler [f];
+                               if (kh != null) {
+                                       rk = new RegistryKey (kh, CombineName (rkey,
+                                               extra), writable);
+                                       key_to_handler [rk] = kh;
+                               } else if (Directory.Exists (f)) {
+                                       kh = new KeyHandler (rkey, f);
+                                       rk = new RegistryKey (kh, CombineName (rkey, extra),
+                                               writable);
+                                       dir_to_handler [f] = kh;
                                        key_to_handler [rk] = kh;
-                                       return rk;
                                }
-                               return null;
+                               return rk;
                        }
                }
 
@@ -224,24 +228,34 @@ namespace Microsoft.Win32 {
                        return String.Concat (rkey.Name, "\\", extra);
                }
                
-               public static KeyHandler Lookup (RegistryKey rkey)
+               public static KeyHandler Lookup (RegistryKey rkey, bool createNonExisting)
                {
                        lock (typeof (KeyHandler)){
                                KeyHandler k = (KeyHandler) key_to_handler [rkey];
                                if (k != null)
                                        return k;
 
+                               // when a non-root key is requested for no keyhandler exist
+                               // then that key must have been marked for deletion
+                               if (!rkey.IsRoot || !createNonExisting)
+                                       return null;
+
                                RegistryHive x = (RegistryHive) rkey.Data;
                                switch (x){
-                               case RegistryHive.ClassesRoot:
-                               case RegistryHive.CurrentConfig:
                                case RegistryHive.CurrentUser:
+                                       string userDir = Path.Combine (UserStore, x.ToString ());
+                                       k = new KeyHandler (rkey, userDir);
+                                       dir_to_handler [userDir] = k;
+                                       break;
+                               case RegistryHive.CurrentConfig:
+                               case RegistryHive.ClassesRoot:
                                case RegistryHive.DynData:
                                case RegistryHive.LocalMachine:
                                case RegistryHive.PerformanceData:
                                case RegistryHive.Users:
-                                       string d = Path.Combine (RegistryStore, x.ToString ());
-                                       k = new KeyHandler (rkey, d);
+                                       string machineDir = Path.Combine (MachineStore, x.ToString ());
+                                       k = new KeyHandler (rkey, machineDir);
+                                       dir_to_handler [machineDir] = k;
                                        break;
                                default:
                                        throw new Exception ("Unknown RegistryHive");
@@ -253,24 +267,63 @@ namespace Microsoft.Win32 {
 
                public static void Drop (RegistryKey rkey)
                {
-                       KeyHandler k = (KeyHandler) key_to_handler [rkey];
-                       if (k == null)
-                               return;
-                       k.valid = false;
-                       dir_to_key.Remove (k.Dir);
-                       key_to_handler.Remove (rkey);
+                       lock (typeof (KeyHandler)) {
+                               KeyHandler k = (KeyHandler) key_to_handler [rkey];
+                               if (k == null)
+                                       return;
+                               key_to_handler.Remove (rkey);
+
+                               // remove cached KeyHandler if no other keys reference it
+                               int refCount = 0;
+                               foreach (DictionaryEntry de in key_to_handler)
+                                       if (de.Value == k)
+                                               refCount++;
+                               if (refCount == 0)
+                                       dir_to_handler.Remove (k.Dir);
+                       }
                }
 
                public static void Drop (string dir)
                {
-                       if (dir_to_key.Contains (dir)){
-                               RegistryKey rkey = (RegistryKey) dir_to_key [dir];
-                               Drop (rkey);
+                       lock (typeof (KeyHandler)) {
+                               KeyHandler kh = (KeyHandler) dir_to_handler [dir];
+                               if (kh == null)
+                                       return;
+
+                               dir_to_handler.Remove (dir);
+
+                               // remove (other) references to keyhandler
+                               ArrayList keys = new ArrayList ();
+                               foreach (DictionaryEntry de in key_to_handler)
+                                       if (de.Value == kh)
+                                               keys.Add (de.Key);
+
+                               foreach (object key in keys)
+                                       key_to_handler.Remove (key);
                        }
                }
 
+               public object GetValue (string name)
+               {
+                       if (IsMarkedForDeletion)
+                               return null;
+
+                       if (name == null)
+                               name = string.Empty;
+                       object value = values [name];
+                       if (value is ExpandString){
+                               return ((ExpandString) value).Expand ();
+                       }
+                       return value;
+               }
+
                public void SetValue (string name, object value)
                {
+                       AssertNotMarkedForDeletion ();
+
+                       if (name == null)
+                               name = string.Empty;
+
                        // immediately convert non-native registry values to string to avoid
                        // returning it unmodified in calls to UnixRegistryApi.GetValue
                        if (value is int || value is string || value is byte[] || value is string[])
@@ -280,6 +333,17 @@ namespace Microsoft.Win32 {
                        SetDirty ();
                }
 
+               public string [] GetValueNames ()
+               {
+                       AssertNotMarkedForDeletion ();
+
+                       ICollection keys = values.Keys;
+
+                       string [] vals = new string [keys.Count];
+                       keys.CopyTo (vals, 0);
+                       return vals;
+               }
+
 #if NET_2_0
                //
                // This version has to do argument validation based on the valueKind
@@ -345,7 +409,7 @@ namespace Microsoft.Win32 {
                        throw new ArgumentException ("Value could not be converted to specified type", "valueKind");
                }
 #endif
-               
+
                void SetDirty ()
                {
                        lock (typeof (KeyHandler)){
@@ -360,15 +424,45 @@ namespace Microsoft.Win32 {
                {
                        Flush ();
                }
-               
+
                public void Flush ()
                {
-                       lock (typeof (KeyHandler)){
-                               Save ();
-                               dirty = false;
+                       lock (typeof (KeyHandler)) {
+                               if (dirty) {
+                                       Save ();
+                                       dirty = false;
+                               }
+                       }
+               }
+
+               public bool ValueExists (string name)
+               {
+                       if (name == null)
+                               name = string.Empty;
+
+                       return values.Contains (name);
+               }
+
+               public int ValueCount {
+                       get {
+                               return values.Keys.Count;
+                       }
+               }
+
+               public bool IsMarkedForDeletion {
+                       get {
+                               return !dir_to_handler.Contains (Dir);
                        }
                }
 
+               public void RemoveValue (string name)
+               {
+                       AssertNotMarkedForDeletion ();
+
+                       values.Remove (name);
+                       SetDirty ();
+               }
+
                ~KeyHandler ()
                {
                        Flush ();
@@ -376,9 +470,9 @@ namespace Microsoft.Win32 {
                
                void Save ()
                {
-                       if (!valid)
+                       if (IsMarkedForDeletion)
                                return;
-                       
+
                        if (!File.Exists (file) && values.Count == 0)
                                return;
 
@@ -395,7 +489,7 @@ namespace Microsoft.Win32 {
                                } else if (val is int){
                                        value.AddAttribute ("type", "int");
                                        value.Text = val.ToString ();
-                               } else if (val is long){
+                               } else if (val is long) {
                                        value.AddAttribute ("type", "qword");
                                        value.Text = val.ToString ();
                                } else if (val is byte []){
@@ -416,25 +510,38 @@ namespace Microsoft.Win32 {
                                se.AddChild (value);
                        }
 
-                       try {
-                               using (FileStream fs = File.Create (file)){
-                                       StreamWriter sw = new StreamWriter (fs);
+                       using (FileStream fs = File.Create (file)){
+                               StreamWriter sw = new StreamWriter (fs);
 
-                                       sw.Write (se.ToString ());
-                                       sw.Flush ();
-                               }
-                       } catch (Exception e){
-                               Console.Error.WriteLine ("When saving {0} got {1}", file, e);
+                               sw.Write (se.ToString ());
+                               sw.Flush ();
                        }
                }
 
-               public static string RegistryStore {
+               private void AssertNotMarkedForDeletion ()
+               {
+                       if (IsMarkedForDeletion)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+               }
+
+               private static string UserStore {
                        get {
                                return Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal),
                                        ".mono/registry");
                        }
                }
 
+               private static string MachineStore {
+                       get {
+                               /*
+                               string machineStore = Environment.GetEnvironmentVariable (MACHINE_STORE_VAR);
+                               if (machineStore != null)
+                                       return machineStore;
+                               */
+                               return UserStore;
+                               // return "/var/lib/mono/registry";
+                       }
+               }
        }
        
        internal class UnixRegistryApi : IRegistryApi {
@@ -461,16 +568,21 @@ namespace Microsoft.Win32 {
 
                public RegistryKey CreateSubKey (RegistryKey rkey, string keyname)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       return self.Ensure (rkey, ToUnix (keyname));
+                       return CreateSubKey (rkey, keyname, true);
                }
 
-               public RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writtable)
+               public RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writable)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       RegistryKey result = self.Probe (rkey, ToUnix (keyname), writtable);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // return null if parent is marked for deletion
+                               return null;
+                       }
+
+                       RegistryKey result = self.Probe (rkey, ToUnix (keyname), writable);
                        if (result == null && IsWellKnownKey (rkey.Name, keyname)) {
-                               result = CreateSubKey (rkey, keyname);
+                               // create the subkey even if its parent was opened read-only
+                               result = CreateSubKey (rkey, keyname, false);
                        }
 
                        return result;
@@ -478,7 +590,11 @@ namespace Microsoft.Win32 {
                
                public void Flush (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, false);
+                       if (self == null) {
+                               // we do not need to flush changes as key is marked for deletion
+                               return;
+                       }
                        self.Flush ();
                }
                
@@ -489,17 +605,14 @@ namespace Microsoft.Win32 {
                
                public object GetValue (RegistryKey rkey, string name, bool return_default_value, object default_value)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-
-                       if (self.values.Contains (name)){
-                               object r = self.values [name];
-
-                               if (r is ExpandString){
-                                       return ((ExpandString)r).Expand ();
-                               }
-                               
-                               return r;
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // key was removed since it was opened
+                               return default_value;
                        }
+
+                       if (self.ValueExists (name))
+                               return self.GetValue (name);
                        if (return_default_value)
                                return default_value;
                        return null;
@@ -507,47 +620,65 @@ namespace Microsoft.Win32 {
                
                public void SetValue (RegistryKey rkey, string name, object value)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
                        self.SetValue (name, value);
                }
 
 #if NET_2_0
                public void SetValue (RegistryKey rkey, string name, object value, RegistryValueKind valueKind)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
                        self.SetValue (name, value, valueKind);
                }
 #endif
-       
+
                public int SubKeyCount (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
                        return Directory.GetDirectories (self.Dir).Length;
                }
                
                public int ValueCount (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-
-                       return self.values.Keys.Count;
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       return self.ValueCount;
                }
                
                public void DeleteValue (RegistryKey rkey, string name, bool throw_if_missing)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // if key is marked for deletion, report success regardless of
+                               // throw_if_missing
+                               return;
+                       }
 
-                       if (throw_if_missing && !self.values.Contains (name))
+                       if (throw_if_missing && !self.ValueExists (name))
                                throw new ArgumentException ("the given value does not exist", "name");
 
-                       self.values.Remove (name);
+                       self.RemoveValue (name);
                }
                
                public void DeleteKey (RegistryKey rkey, string keyname, bool throw_if_missing)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       string dir = Path.Combine (self.Dir, ToUnix (keyname));
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // key is marked for deletion
+                               if (!throw_if_missing)
+                                       return;
+                               throw new ArgumentException ("the given value does not exist", "value");
+                       }
 
+                       string dir = Path.Combine (self.Dir, ToUnix (keyname));
+                       
                        if (Directory.Exists (dir)){
                                Directory.Delete (dir, true);
                                KeyHandler.Drop (dir);
@@ -557,7 +688,7 @@ namespace Microsoft.Win32 {
                
                public string [] GetSubKeyNames (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
                        DirectoryInfo selfDir = new DirectoryInfo (self.Dir);
                        DirectoryInfo[] subDirs = selfDir.GetDirectories ();
                        string[] subKeyNames = new string[subDirs.Length];
@@ -570,17 +701,23 @@ namespace Microsoft.Win32 {
                
                public string [] GetValueNames (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       ICollection keys = self.values.Keys;
-
-                       string [] vals = new string [keys.Count];
-                       keys.CopyTo (vals, 0);
-                       return vals;
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       return self.GetValueNames ();
                }
 
                public string ToString (RegistryKey rkey)
                {
                        return rkey.Name;
                }
+
+               private RegistryKey CreateSubKey (RegistryKey rkey, string keyname, bool writable)
+               {
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       return self.Ensure (rkey, ToUnix (keyname), writable);
+               }
        }
 }
index 5272db26ff64cc5f82785449d8f0c913d2b53944..a2e59fb068501aac7404541d60ecc9c9fc980aaa 100644 (file)
@@ -128,6 +128,11 @@ namespace Microsoft.Win32
                                : (IntPtr) key.Data;
                }
 
+               static bool IsHandleValid (RegistryKey key)
+               {
+                       return key.Data != null;
+               }
+
                /// <summary>
                ///     Acctually read a registry value. Requires knoledge of the
                ///     value's type and size.
@@ -140,7 +145,7 @@ namespace Microsoft.Win32
                        IntPtr handle = GetHandle (rkey);
                        int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
 
-                       if (result == Win32ResultCode.FileNotFound) {
+                       if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) {
                                if (returnDefaultValue) {
                                        return defaultValue;
                                }
@@ -268,6 +273,9 @@ namespace Microsoft.Win32
                                                        rawValue.Length * NativeBytesPerCharacter);
                        }
 
+                       if (result == Win32ResultCode.MarkedForDeletion)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+
                        // handle the result codes
                        if (result != Win32ResultCode.Success)
                        {
@@ -301,7 +309,10 @@ namespace Microsoft.Win32
                        
                        for (index = 0; true; index ++) {
                                result = RegEnumKey (handle, index, stringBuffer, BufferMaxLength);
-                               
+
+                               if (result == Win32ResultCode.MarkedForDeletion)
+                                       throw RegistryKey.CreateMarkedForDeletionException ();
+
                                if (result == Win32ResultCode.Success)
                                        continue;
                                
@@ -328,7 +339,10 @@ namespace Microsoft.Win32
                                                       buffer, ref bufferCapacity,
                                                       IntPtr.Zero, ref type, 
                                                       IntPtr.Zero, IntPtr.Zero);
-                               
+
+                               if (result == Win32ResultCode.MarkedForDeletion)
+                                       throw RegistryKey.CreateMarkedForDeletionException ();
+
                                if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
                                        continue;
                                
@@ -341,32 +355,36 @@ namespace Microsoft.Win32
                        return index;
                }
                
-               public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writtable)
+               public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
                {
                        int access = OpenRegKeyRead;
-                       if (writtable) access |= OpenRegKeyWrite;
+                       if (writable) access |= OpenRegKeyWrite;
                        IntPtr handle = GetHandle (rkey);
                        
                        IntPtr subKeyHandle;
                        int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
 
-                       if (result == Win32ResultCode.FileNotFound)
+                       if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
                                return null;
                        
                        if (result != Win32ResultCode.Success)
                                GenerateException (result);
                        
-                       return new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
+                       return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
                }
 
                public void Flush (RegistryKey rkey)
                {
+                       if (!IsHandleValid (rkey))
+                               return;
                        IntPtr handle = GetHandle (rkey);
                        RegFlushKey (handle);
                }
 
                public void Close (RegistryKey rkey)
                {
+                       if (!IsHandleValid (rkey))
+                               return;
                        IntPtr handle = GetHandle (rkey);
                        RegCloseKey (handle);
                }
@@ -377,13 +395,15 @@ namespace Microsoft.Win32
                        IntPtr subKeyHandle;
                        int result = RegCreateKey (handle , keyName, out subKeyHandle);
 
+                       if (result == Win32ResultCode.MarkedForDeletion)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+
                        if (result != Win32ResultCode.Success) {
                                GenerateException (result);
                        }
                        
-                       RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
-
-                       return subKey;
+                       return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
+                               true);
                }
 
                public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
@@ -405,7 +425,10 @@ namespace Microsoft.Win32
                {
                        IntPtr handle = GetHandle (rkey);
                        int result = RegDeleteValue (handle, value);
-                       
+
+                       if (result == Win32ResultCode.MarkedForDeletion)
+                               return;
+
                        if (result == Win32ResultCode.FileNotFound){
                                if (shouldThrowWhenKeyMissing)
                                        throw new ArgumentException ("value " + value);
@@ -462,7 +485,10 @@ namespace Microsoft.Win32
                                
                                if (result == Win32ResultCode.NoMoreEntries)
                                        break;
-                                       
+
+                               if (result == Win32ResultCode.MarkedForDeletion)
+                                       throw RegistryKey.CreateMarkedForDeletionException ();
+
                                GenerateException (result);
                        }
 
index 19883945b88b719c15199de6124855a0f7ad2c5b..2dc103e414a5f1eccc9812417b0c9a4fd174c0dc 100644 (file)
@@ -52,6 +52,8 @@ namespace Microsoft.Win32
                public const int AccessDenied = 5;
                public const int InvalidParameter = 87;
                public const int MoreData = 234;
-               public const int NoMoreEntries = 259;   
+               public const int NoMoreEntries = 259;
+               public const int MarkedForDeletion = 1018;
+
        }
 }
index c1754ff7d60eb3fec76353a3f38588c93389442b..a1ba02ae85cfd63945b44785f838554a26e0b076 100644 (file)
@@ -1,3 +1,7 @@
+2006-08-14  Gert Driesen  <drieseng@users.sourceforge.net>
+
+       * RegistryKeyTest.cs: Added large batch of tests.
+
 2006-05-28  Gert Driesen  <drieseng@users.sourceforge.net>
 
        * RegistryKeyTest.cs: Added test for bug #78519.
index 439ac715b95fba65570622f65cf1ce2803f6ecac..d3be666b13749466f5aa14faebacbad78957f982 100644 (file)
@@ -3,15 +3,19 @@
 //
 // Authors:
 //     mei (mei@work.email.ne.jp)
-//      Robert Jordan (robertj@gmx.net)
+//     Robert Jordan (robertj@gmx.net)
+//     Gert Driesen (drieseng@users.sourceforge.net)
 //
 // (C) 2005 mei
 // (C) 2004, 2005 Novell (http://www.novell.com)
 //
 
-using NUnit.Framework;
-using Microsoft.Win32;
 using System;
+using System.IO;
+
+using Microsoft.Win32;
+
+using NUnit.Framework;
 
 namespace MonoTests.Microsoft.Win32
 {
@@ -20,78 +24,1197 @@ namespace MonoTests.Microsoft.Win32
        {
                private const string mimeroot = @"MIME\Database\Content Type";
                [Test]
-               [Category("NotWorking")]
-               // This will not work on Linux ever
-               public void TestGetValue ()
+               [Category("NotWorking")]
+               // This will not work on Linux ever
+               public void TestGetValue ()
+               {
+                       RegistryKey root = Registry.ClassesRoot;
+                       RegistryKey key;
+                       
+                       key = root.OpenSubKey (mimeroot + @"\audio/wav");
+                       Assert.AreEqual (".wav", key.GetValue ("Extension"), "GetValue #1");
+                       key = root.OpenSubKey (mimeroot + @"\text/x-scriptlet");
+                       Assert.AreEqual (null, key.GetValue ("Extension"), "GetValue #2");
+               }
+
+               //
+               // Unit test for bug #77212
+               //
+               [Test]
+               public void TestHandle ()
+               {
+                       // this test is for Windows
+                       int p = (int) Environment.OSVersion.Platform;
+                       if ((p == 4) || (p == 128))
+                               return;
+
+                       // this regpath always exists under windows
+                       RegistryKey k = Registry.CurrentUser
+                               .OpenSubKey ("Software", false)
+                               .OpenSubKey ("Microsoft", false)
+                               .OpenSubKey ("Windows", false);
+                       
+                       Assert.IsNotNull (k, "#01");
+               }
+
+               [Test]
+               public void OpenSubKey ()
+               {
+                       RegistryKey key = Registry.LocalMachine;
+
+                       // HKEY_LOCAL_MACHINE\software should always exist on Windows
+                       // and is automatically created on Linux
+                       Assert.IsNotNull (key.OpenSubKey ("Software"), "#A1");
+                       Assert.IsNotNull (key.OpenSubKey ("soFtware"), "#A2");
+
+                       key = Registry.CurrentUser;
+
+                       // HKEY_CURRENT_USER\software should always exist on Windows
+                       // and is automatically created on Linux
+                       Assert.IsNotNull (key.OpenSubKey ("Software"), "#B1");
+                       Assert.IsNotNull (key.OpenSubKey ("soFtware"), "#B2");
+
+                       key = Registry.Users;
+
+                       // HKEY_USERS\software should not exist on Windows, and should not
+                       // be created automatically on Linux
+                       Assert.IsNull (key.OpenSubKey ("Software"), "#C1");
+                       Assert.IsNull (key.OpenSubKey ("soFtware"), "#C2");
+               }
+
+               [Test]
+               public void OpenSubKey_Key_DoesNotExist ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName), "#1"); // read-only
+                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName, true), "#2"); // writable
+               }
+
+               [Test]
+               public void OpenSubKey_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#1");
+                                       RegistryKey subKey = createdKey.CreateSubKey ("monotemp");
+                                       subKey.Close ();
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       Assert.IsNotNull (createdKey, "#2");
+                                       using (RegistryKey subKey = createdKey.OpenSubKey ("monotemp")) {
+                                               Assert.IsNotNull (createdKey, "#3");
+                                       }
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+
+                                       // read-only
+                                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName), "#4");
+                                       Assert.IsNull (createdKey.OpenSubKey ("monotemp"), "#5"); // read-only
+                                       // writable
+                                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName, true), "#6");
+                                       Assert.IsNull (createdKey.OpenSubKey ("monotemp", true), "#7"); 
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentNullException))]
+               public void OpenSubKey_Name_Null ()
+               {
+                       Registry.CurrentUser.OpenSubKey (null);
+               }
+
+               [Test]
+               [Category ("NotWorking")] // MS should not allow this
+               public void OpenSubKey_Name_Empty ()
+               {
+                       // read-only
+                       using (RegistryKey emptyKey = Registry.CurrentUser.OpenSubKey (string.Empty)) {
+                               Assert.IsNotNull (emptyKey, "#1");
+                       }
+                       // writable
+                       using (RegistryKey emptyKey = Registry.CurrentUser.OpenSubKey (string.Empty, true)) {
+                               Assert.IsNotNull (emptyKey, "#1");
+                       }
+               }
+
+               [Test]
+               public void CreateSubKey ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName);
+                       try {
+                               // check if key was successfully created
+                               Assert.IsNotNull (createdKey, "#1");
+                               // software subkey should not be created automatically
+                               Assert.IsNull (createdKey.OpenSubKey ("software"), "#2");
+                       } finally {
+                               // clean-up
+                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                       }
+               }
+
+               [Test]
+               public void CreateSubKey_Key_ReadOnly ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software")) {
+                               RegistryKey createdKey = null;
+                               try {
+                                       try {
+                                               createdKey = softwareKey.CreateSubKey (subKeyName);
+                                               Assert.Fail ("#1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key.
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#2");
+                                               Assert.IsNotNull (ex.Message, "#3");
+                                               Assert.IsNull (ex.InnerException, "#4");
+                                       }
+                               } finally {
+                                       if (createdKey != null)
+                                               createdKey.Close ();
+                               }
+                       }
+               }
+
+               [Test]
+               public void CreateSubKey_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       using (RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName)) {
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                               Assert.IsNull (softwareKey.OpenSubKey (subKeyName), "#1");
+                                               try {
+                                                       createdKey.CreateSubKey ("test");
+                                                       Assert.Fail ("#2");
+                                               } catch (IOException ex) {
+                                                       // Illegal operation attempted on a registry key that
+                                                       // has been marked for deletion
+                                                       Assert.AreEqual (typeof (IOException), ex.GetType (), "#3");
+                                                       Assert.IsNotNull (ex.Message, "#4");
+                                                       Assert.IsNull (ex.InnerException, "#5");
+                                               }
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               [Category ("NotWorking")] // MS should not allow this
+               public void CreateSubKey_Name_Empty ()
+               {
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               using (RegistryKey emptyKey = softwareKey.CreateSubKey (string.Empty)) {
+                                       Assert.IsNotNull (emptyKey, "#1");
+                                       emptyKey.SetValue ("name1", "value1");
+                               }
+                       }
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentNullException))]
+               public void CreateSubKey_Name_Null ()
+               {
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               softwareKey.CreateSubKey (null);
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKey ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#1");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey, "#2");
+                                       Registry.CurrentUser.DeleteSubKey (subKeyName);
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNull (createdKey, "#3");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKey_Key_HasChildKeys ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#1");
+                                       RegistryKey subKey = createdKey.CreateSubKey ("monotemp");
+                                       subKey.Close ();
+                               }
+                               try {
+                                       Registry.CurrentUser.DeleteSubKey (subKeyName);
+                                       Assert.Fail ("#2");
+                               } catch (InvalidOperationException ex) {
+                                       // Registry key has subkeys and recursive removes are not
+                                       // supported by this method.
+                                       Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#3");
+                                       Assert.IsNotNull (ex.Message, "#4");
+                                       Assert.IsNull (ex.InnerException, "#5");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKey_Key_ReadOnly ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                                       RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName);
+                                       createdKey.Close ();
+                               }
+
+                               using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software")) {
+                                       try {
+                                               softwareKey.DeleteSubKey (subKeyName);
+                                               Assert.Fail ("#1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#2");
+                                               Assert.IsNotNull (ex.Message, "#3");
+                                               Assert.IsNull (ex.InnerException, "#4");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKey_Key_DoesNotExist ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               Registry.CurrentUser.DeleteSubKey (subKeyName);
+                               Assert.Fail ("#A1");
+                       } catch (ArgumentException ex) {
+                               // Cannot delete a subkey tree because the subkey does not exist
+                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#A2");
+                               Assert.IsNotNull (ex.Message, "#A3");
+                               Assert.IsNull (ex.InnerException, "#A4");
+                       }
+
+                       try {
+                               Registry.CurrentUser.DeleteSubKey (subKeyName, true);
+                               Assert.Fail ("#B1");
+                       } catch (ArgumentException ex) {
+                               // Cannot delete a subkey tree because the subkey does not exist
+                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#B2");
+                               Assert.IsNotNull (ex.Message, "#B3");
+                               Assert.IsNull (ex.InnerException, "#B4");
+                       }
+
+                       Registry.CurrentUser.DeleteSubKey (subKeyName, false);
+               }
+
+               [Test]
+               public void DeleteSubKey_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#1");
+                                       RegistryKey subKey = createdKey.CreateSubKey ("monotemp");
+                                       subKey.Close ();
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       Assert.IsNotNull (createdKey, "#2");
+                                       using (RegistryKey subKey = createdKey.OpenSubKey ("monotemp")) {
+                                               Assert.IsNotNull (createdKey, "#3");
+                                       }
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName), "#4");
+                                       try {
+                                               createdKey.DeleteSubKey ("monotemp");
+                                               Assert.Fail ("#5");
+                                       } catch (ArgumentException ex) {
+                                               // Cannot delete a subkey tree because the subkey does
+                                               // not exist
+                                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#6");
+                                               Assert.IsNotNull (ex.Message, "#7");
+                                               Assert.IsNull (ex.InnerException, "#8");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               [Category ("NotWorking")] // MS should not allow this
+               public void DeleteSubKey_Name_Empty ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName);
+                                       createdKey.DeleteSubKey (string.Empty);
+                                       createdKey.Close ();
+
+                                       createdKey = softwareKey.OpenSubKey (subKeyName);
+                                       Assert.IsNull (createdKey, "#1");
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null)
+                                                       createdKey.Close ();
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKey_Name_Null ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName);
+                                       try {
+                                               createdKey.DeleteSubKey (null);
+                                               Assert.Fail ("#1");
+                                       } catch (ArgumentNullException ex) {
+                                               // Value cannot be null. Parameter name: subkey
+                                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                                               Assert.IsNotNull (ex.Message, "#3");
+                                               Assert.IsNull (ex.InnerException, "#4");
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null)
+                                                       createdKey.Close ();
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKeyTree ()
+               {
+                       // TODO: 
+                       // - remove key with subkeys
+                       // - remove key of which some subkeys are marked for deletion
+                       // - remove key with values
+               }
+
+               [Test]
+               [ExpectedException (typeof (ArgumentException))]
+               public void DeleteSubKeyTree_Key_DoesNotExist ()
+               {
+                       // Cannot delete a subkey tree because the subkey does not exist
+                       string subKeyName = Guid.NewGuid ().ToString ();
+                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+               }
+
+               [Test]
+               public void DeleteSubKeyTree_Key_ReadOnly ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                                       RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName);
+                                       createdKey.Close ();
+                               }
+
+                               using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software")) {
+                                       try {
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                               Assert.Fail ("#1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#2");
+                                               Assert.IsNotNull (ex.Message, "#3");
+                                               Assert.IsNull (ex.InnerException, "#4");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null)
+                                                       createdKey.Close ();
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKeyTree_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#1");
+                                       RegistryKey subKey = createdKey.CreateSubKey ("monotemp");
+                                       subKey.Close ();
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       Assert.IsNotNull (createdKey, "#2");
+                                       using (RegistryKey subKey = createdKey.OpenSubKey ("monotemp")) {
+                                               Assert.IsNotNull (createdKey, "#3");
+                                       }
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName), "#4");
+                                       try {
+                                               createdKey.DeleteSubKeyTree ("monotemp");
+                                               Assert.Fail ("#5");
+                                       } catch (ArgumentException ex) {
+                                               // Cannot delete a subkey tree because the subkey does
+                                               // not exist
+                                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#6");
+                                               Assert.IsNotNull (ex.Message, "#7");
+                                               Assert.IsNull (ex.InnerException, "#8");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               [Category ("NotWorking")] // MS should not allow this
+               public void DeleteSubKeyTree_Name_Empty ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName);
+                                       createdKey.DeleteSubKeyTree (string.Empty);
+                                       createdKey.Close ();
+
+                                       createdKey = softwareKey.OpenSubKey (subKeyName);
+                                       Assert.IsNull (createdKey, "#1");
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null)
+                                                       createdKey.Close ();
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteSubKeyTree_Name_Null ()
+               {
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       softwareKey.DeleteSubKeyTree (null);
+                                       Assert.Fail ("#1");
+                               } catch (ArgumentNullException ex) {
+                                       // Value cannot be null. Parameter name: subkey
+                                       Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
+                                       Assert.IsNotNull (ex.Message, "#3");
+                                       Assert.IsNull (ex.InnerException, "#4");
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteValue ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#A1");
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#A2");
+                                       Assert.AreEqual (2, names.Length, "#A3");
+                                       Assert.IsNotNull (names [0], "#A4");
+                                       Assert.AreEqual ("name1", names [0], "#A5");
+                                       Assert.IsNotNull (createdKey.GetValue ("name1"), "#A6");
+                                       Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#A7");
+                                       Assert.AreEqual ("name2", names [1], "#A8");
+                                       Assert.IsNotNull (createdKey.GetValue ("name2"), "#A9");
+                                       Assert.AreEqual ("value2", createdKey.GetValue ("name2"), "#A10");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       Assert.IsNotNull (createdKey, "#B1");
+                                       createdKey.DeleteValue ("name1");
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#B2");
+                                       Assert.AreEqual (1, names.Length, "#B3");
+                                       Assert.IsNotNull (names [0], "#B4");
+                                       Assert.AreEqual ("name2", names [0], "#B5");
+                                       Assert.IsNotNull (createdKey.GetValue ("name2"), "#B6");
+                                       Assert.AreEqual ("value2", createdKey.GetValue ("name2"), "#B7");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#C1");
+                                       Assert.AreEqual (1, names.Length, "#C2");
+                                       Assert.IsNotNull (names [0], "#C3");
+                                       Assert.AreEqual ("name2", names [0], "#C4");
+                                       Assert.IsNotNull (createdKey.GetValue ("name2"), "#C5");
+                                       Assert.AreEqual ("value2", createdKey.GetValue ("name2"), "#C6");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteValue_Key_ReadOnly ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       try {
+                                               // deleting value that exists
+                                               createdKey.DeleteValue ("name1");
+                                               Assert.Fail ("#A1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#A2");
+                                               Assert.IsNotNull (ex.Message, "#A3");
+                                               Assert.IsNull (ex.InnerException, "#A4");
+                                       }
+
+                                       try {
+                                               // deleting value that exists
+                                               createdKey.DeleteValue ("name1", true);
+                                               Assert.Fail ("#B1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#B2");
+                                               Assert.IsNotNull (ex.Message, "#B3");
+                                               Assert.IsNull (ex.InnerException, "#B4");
+                                       }
+
+                                       try {
+                                               // deleting value that exists
+                                               createdKey.DeleteValue ("name1", false);
+                                               Assert.Fail ("#C1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#C2");
+                                               Assert.IsNotNull (ex.Message, "#C3");
+                                               Assert.IsNull (ex.InnerException, "#C4");
+                                       }
+
+                                       try {
+                                               // deleting value that does not exist
+                                               createdKey.DeleteValue ("name2");
+                                               Assert.Fail ("#D1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#D2");
+                                               Assert.IsNotNull (ex.Message, "#D3");
+                                               Assert.IsNull (ex.InnerException, "#D4");
+                                       }
+
+                                       try {
+                                               // deleting value that does not exist
+                                               createdKey.DeleteValue ("name2", true);
+                                               Assert.Fail ("#E1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#E2");
+                                               Assert.IsNotNull (ex.Message, "#E3");
+                                               Assert.IsNull (ex.InnerException, "#E4");
+                                       }
+
+                                       try {
+                                               // deleting value that does not exist
+                                               createdKey.DeleteValue ("name2", false);
+                                               Assert.Fail ("#F1");
+                                       } catch (UnauthorizedAccessException ex) {
+                                               // Cannot write to the registry key
+                                               Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#F2");
+                                               Assert.IsNotNull (ex.Message, "#F3");
+                                               Assert.IsNull (ex.InnerException, "#F4");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteValue_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#1");
+                                       createdKey.SetValue ("name1", "value1");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       Assert.IsNotNull (createdKey, "#2");
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       Assert.IsNull (Registry.CurrentUser.OpenSubKey (subKeyName), "#3");
+
+                                       createdKey.DeleteValue ("name1");
+                                       createdKey.DeleteValue ("name1", true);
+                                       createdKey.DeleteValue ("name1", false);
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteValue_Value_DoesNotExist ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#A1");
+                                       createdKey.SetValue ("name1", "value1");
+
+                                       try {
+                                               createdKey.DeleteValue ("name2");
+                                               Assert.Fail ("#B1");
+                                       } catch (ArgumentException ex) {
+                                               // No value exists with that name
+                                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#B2");
+                                               Assert.IsNotNull (ex.Message, "#B3");
+                                               Assert.IsNull (ex.InnerException, "#B4");
+                                       }
+
+                                       try {
+                                               createdKey.DeleteValue ("name2", true);
+                                               Assert.Fail ("#C1");
+                                       } catch (ArgumentException ex) {
+                                               // No value exists with that name
+                                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#C2");
+                                               Assert.IsNotNull (ex.Message, "#C3");
+                                               Assert.IsNull (ex.InnerException, "#C4");
+                                       }
+
+                                       createdKey.DeleteValue ("name2", false);
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteValue_Name_Empty ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue (string.Empty, "value2");
+
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#A1");
+                                       Assert.AreEqual (2, names.Length, "#A2");
+                                       Assert.IsNotNull (names [0], "#A3");
+                                       /*
+                                       Assert.AreEqual ("name1", names [0], "#A4");
+                                       */
+                                       Assert.IsNotNull (createdKey.GetValue ("name1"), "#A5");
+                                       Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#A6");
+                                       Assert.IsNotNull (names [1], "#A7");
+                                       /*
+                                       Assert.AreEqual (string.Empty, names [1], "#A8");
+                                       */
+                                       Assert.IsNotNull (createdKey.GetValue (string.Empty), "#A9");
+                                       Assert.AreEqual ("value2", createdKey.GetValue (string.Empty), "#A10");
+
+                                       createdKey.DeleteValue (string.Empty);
+
+                                       names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#B1");
+                                       Assert.AreEqual (1, names.Length, "#B2");
+                                       Assert.IsNotNull (names [0], "#B3");
+                                       Assert.AreEqual ("name1", names [0], "#B4");
+                                       Assert.IsNotNull (createdKey.GetValue ("name1"), "#B5");
+                                       Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#B6");
+
+                                       try {
+                                               createdKey.DeleteValue (string.Empty);
+                                               Assert.Fail ("#C1");
+                                       } catch (ArgumentException ex) {
+                                               // No value exists with that name
+                                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#C2");
+                                               Assert.IsNotNull (ex.Message, "#C3");
+                                               Assert.IsNull (ex.InnerException, "#C4");
+                                       }
+
+                                       try {
+                                               createdKey.DeleteValue (string.Empty, true);
+                                               Assert.Fail ("#D1");
+                                       } catch (ArgumentException ex) {
+                                               // No value exists with that name
+                                               Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#D2");
+                                               Assert.IsNotNull (ex.Message, "#D3");
+                                               Assert.IsNull (ex.InnerException, "#D4");
+                                       }
+
+                                       createdKey.DeleteValue (string.Empty, false);
+
+                                       names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#E1");
+                                       Assert.AreEqual (1, names.Length, "#E2");
+                                       Assert.IsNotNull (names [0], "#E3");
+                                       Assert.AreEqual ("name1", names [0], "#E4");
+                                       Assert.IsNotNull (createdKey.GetValue ("name1"), "#E5");
+                                       Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#E6");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void DeleteValue_Name_Null ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue (null, "value2");
+
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#A1");
+                                       Assert.AreEqual (2, names.Length, "#A2");
+                                       Assert.IsNotNull (names [0], "#A3");
+                                       /*
+                                       Assert.AreEqual ("name1", names [0], "#A4");
+                                       */
+                                       Assert.IsNotNull (createdKey.GetValue ("name1"), "#A5");
+                                       Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#A6");
+                                       Assert.IsNotNull (names [1], "#A7");
+                                       /*
+                                       Assert.AreEqual (string.Empty, names [1], "#A8");
+                                       */
+                                       Assert.IsNotNull (createdKey.GetValue (null), "#A9");
+                                       Assert.AreEqual ("value2", createdKey.GetValue (null), "#A10");
+
+                                       try {
+                                               createdKey.DeleteValue (null);
+                                               Assert.Fail ("#B1");
+                                       } catch (ArgumentNullException ex) {
+                                               // Value cannot be null. Parameter name: name
+                                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#B2");
+                                               Assert.IsNotNull (ex.Message, "#B3");
+                                               Assert.IsNull (ex.InnerException, "#B4");
+                                       }
+
+                                       try {
+                                               createdKey.DeleteValue (null, true);
+                                               Assert.Fail ("#C1");
+                                       } catch (ArgumentNullException ex) {
+                                               // Value cannot be null. Parameter name: name
+                                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#C2");
+                                               Assert.IsNotNull (ex.Message, "#C3");
+                                               Assert.IsNull (ex.InnerException, "#C4");
+                                       }
+
+                                       try {
+                                               createdKey.DeleteValue (null, false);
+                                               Assert.Fail ("#D1");
+                                       } catch (ArgumentNullException ex) {
+                                               // Value cannot be null. Parameter name: name
+                                               Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#D2");
+                                               Assert.IsNotNull (ex.Message, "#D3");
+                                               Assert.IsNull (ex.InnerException, "#D4");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void GetValue ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey.GetValue ("name1"), "#1");
+                                       Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#2");
+                                       Assert.IsNotNull (createdKey.GetValue ("name2"), "#3");
+                                       Assert.AreEqual ("value2", createdKey.GetValue ("name2"), "#4");
+                                       Assert.IsNull (createdKey.GetValue ("name3"), "#5");
+                                       Assert.AreEqual ("value3", createdKey.GetValue ("name3", "value3"), "#6");
+                                       Assert.IsNull (createdKey.GetValue ("name3", null), "#7");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void GetValue_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+
+                                       Assert.IsNull (createdKey.GetValue ("name1"), "#1");
+                                       Assert.IsNotNull (createdKey.GetValue ("name1", "default"), "#2");
+                                       Assert.AreEqual ("default", createdKey.GetValue ("name1", "default"), "#3");
+                                       Assert.IsNull (createdKey.GetValue ("name3"), "#3");
+                                       Assert.IsNotNull (createdKey.GetValue ("name3", "default"), "#4");
+                                       Assert.AreEqual ("default", createdKey.GetValue ("name3", "default"), "#5");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void GetValue_Name_Empty ()
                {
-                       RegistryKey root = Registry.ClassesRoot;
-                       RegistryKey key;
-                       
-                       key = root.OpenSubKey (mimeroot + @"\audio/wav");
-                       Assert.AreEqual (".wav", key.GetValue ("Extension"), "GetValue #1");
-                       key = root.OpenSubKey (mimeroot + @"\text/x-scriptlet");
-                       Assert.AreEqual (null, key.GetValue ("Extension"), "GetValue #2");
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
+
+                                       Assert.IsNull (createdKey.GetValue (string.Empty), "#A1");
+                                       Assert.IsNotNull (createdKey.GetValue (string.Empty, "default"), "#A2");
+                                       Assert.AreEqual ("default", createdKey.GetValue (string.Empty, "default"), "#A3");
+                                       Assert.IsNull (createdKey.GetValue (string.Empty, null), "#A4");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNull (createdKey.GetValue (string.Empty), "#B1");
+                                       Assert.IsNotNull (createdKey.GetValue (string.Empty, "default"), "#B2");
+                                       Assert.AreEqual ("default", createdKey.GetValue (string.Empty, "default"), "#B3");
+                                       Assert.IsNull (createdKey.GetValue (string.Empty, null), "#B4");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       createdKey.SetValue (string.Empty, "value1");
+                                       Assert.IsNotNull (createdKey.GetValue (string.Empty), "#C1");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (string.Empty), "#C2");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (string.Empty, "default"), "#C3");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (string.Empty, null), "#C4");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey.GetValue (string.Empty), "#D1");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (string.Empty), "#D2");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (string.Empty, "default"), "#D3");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (string.Empty, null), "#D4");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
                }
 
-               //
-               // Unit test for bug #77212
-               //
                [Test]
-               public void TestHandle ()
+               public void GetValue_Name_Null ()
                {
-                       // this test is for Windows
-                       int p = (int) Environment.OSVersion.Platform;
-                       if ((p == 4) || (p == 128))
-                               return;
+                       string subKeyName = Guid.NewGuid ().ToString ();
 
-                       // this regpath always exists under windows
-                       RegistryKey k = Registry.CurrentUser
-                               .OpenSubKey ("Software", false)
-                               .OpenSubKey ("Microsoft", false)
-                               .OpenSubKey ("Windows", false);
-                       
-                       Assert.IsNotNull (k, "#01");
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
+
+                                       Assert.IsNull (createdKey.GetValue (null), "#A1");
+                                       Assert.IsNotNull (createdKey.GetValue (null, "default"), "#A2");
+                                       Assert.AreEqual ("default", createdKey.GetValue (null, "default"), "#A3");
+                                       Assert.IsNull (createdKey.GetValue (null, null), "#A4");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNull (createdKey.GetValue (null), "#B1");
+                                       Assert.IsNotNull (createdKey.GetValue (null, "default"), "#B2");
+                                       Assert.AreEqual ("default", createdKey.GetValue (null, "default"), "#B3");
+                                       Assert.IsNull (createdKey.GetValue (null, null), "#B4");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                       createdKey.SetValue (string.Empty, "value1");
+                                       Assert.IsNotNull (createdKey.GetValue (null), "#C1");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (null), "#C2");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (null, "default"), "#C3");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (null, null), "#C4");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey.GetValue (null), "#D1");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (null), "#D2");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (null, "default"), "#D3");
+                                       Assert.AreEqual ("value1", createdKey.GetValue (null, null), "#D4");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
                }
 
                [Test]
-               public void OpenSubKeyTest ()
+               public void GetValueNames ()
                {
-                       RegistryKey key = Registry.LocalMachine;
-
-                       // HKEY_LOCAL_MACHINE\software should always exist on Windows
-                       // and is automatically created on Linux
-                       Assert.IsNotNull (key.OpenSubKey ("Software"), "#A1");
-                       Assert.IsNotNull (key.OpenSubKey ("soFtware"), "#A2");
+                       string subKeyName = Guid.NewGuid ().ToString ();
 
-                       key = Registry.CurrentUser;
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#A1");
+                                       Assert.AreEqual (0, names.Length, "#A2");
 
-                       // HKEY_CURRENT_USER\software should always exist on Windows
-                       // and is automatically created on Linux
-                       Assert.IsNotNull (key.OpenSubKey ("Software"), "#B1");
-                       Assert.IsNotNull (key.OpenSubKey ("soFtware"), "#B2");
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
 
-                       key = Registry.Users;
+                                       names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#B1");
+                                       Assert.AreEqual (2, names.Length, "#B2");
+                                       // TODO: check content, but Mono uses hashtable so names
+                                       // are not returned in order
+                               }
 
-                       // HKEY_USERS\software should not exist on Windows, and should not
-                       // be created automatically on Linux
-                       Assert.IsNull (key.OpenSubKey ("Software"), "#C1");
-                       Assert.IsNull (key.OpenSubKey ("soFtware"), "#C2");
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#C1");
+                                       Assert.AreEqual (2, names.Length, "#C2");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
                }
 
                [Test]
-               public void CreateSubKeyTest ()
+               public void GetValueNames_Key_Removed ()
                {
                        string subKeyName = Guid.NewGuid ().ToString ();
 
-                       RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName);
                        try {
-                               // check if key was successfully created
-                               Assert.IsNotNull (createdKey, "#1");
-                               // software subkey should not be created automatically
-                               Assert.IsNull (createdKey.OpenSubKey ("software"), "#2");
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.SetValue ("name1", "value1");
+                                       createdKey.SetValue ("name2", "value2");
+
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#A1");
+                                       Assert.AreEqual (2, names.Length, "#A2");
+                               }
+
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       string [] names = createdKey.GetValueNames ();
+                                       Assert.IsNotNull (names, "#B1");
+                                       Assert.AreEqual (2, names.Length, "#B2");
+
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+
+                                       try {
+                                               createdKey.GetValueNames ();
+                                               Assert.Fail ("#C1");
+                                       } catch (IOException ex) {
+                                               // Illegal operation attempted on a registry key that
+                                               // has been marked for deletion
+                                               Assert.AreEqual (typeof (IOException), ex.GetType (), "#C2");
+                                               Assert.IsNotNull (ex.Message, "#C3");
+                                               Assert.IsNull (ex.InnerException, "#C4");
+                                       }
+                               }
                        } finally {
-                               // clean-up
-                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
                        }
                }
 
@@ -121,6 +1244,74 @@ namespace MonoTests.Microsoft.Win32
                        }
                }
 
+               [Test]
+               public void SetValue_Name_Null ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName);
+                       try {
+                               createdKey.SetValue (null, "value1");
+                               string [] names = createdKey.GetValueNames ();
+                               Assert.IsNotNull (names, "#A1");
+                               Assert.AreEqual (1, names.Length, "#A2");
+                               Assert.IsNotNull (names [0], "#A3");
+                               Assert.AreEqual (string.Empty, names [0], "#A4");
+                               Assert.IsNotNull (createdKey.GetValue (string.Empty), "#A5");
+                               Assert.AreEqual ("value1", createdKey.GetValue (string.Empty), "#A6");
+                               Assert.IsNotNull (createdKey.GetValue (null), "#A7");
+                               Assert.AreEqual ("value1", createdKey.GetValue (null), "#A8");
+
+                               createdKey.SetValue (string.Empty, "value2");
+                               names = createdKey.GetValueNames ();
+                               Assert.IsNotNull (names, "#B1");
+                               Assert.AreEqual (1, names.Length, "#B2");
+                               Assert.IsNotNull (names [0], "#B3");
+                               Assert.AreEqual (string.Empty, names [0], "#B4");
+                               Assert.IsNotNull (createdKey.GetValue (string.Empty), "#B5");
+                               Assert.AreEqual ("value2", createdKey.GetValue (string.Empty), "#B6");
+                               Assert.IsNotNull (createdKey.GetValue (null), "#B7");
+                               Assert.AreEqual ("value2", createdKey.GetValue (null), "#B8");
+                       } finally {
+                               // clean-up
+                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                       }
+               }
+
+               [Test]
+               public void SetValue_Name_Empty ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName);
+                       try {
+                               createdKey.SetValue (string.Empty, "value1");
+                               string [] names = createdKey.GetValueNames ();
+                               Assert.IsNotNull (names, "#A1");
+                               Assert.AreEqual (1, names.Length, "#A2");
+                               Assert.IsNotNull (names [0], "#A3");
+                               Assert.AreEqual (string.Empty, names [0], "#A4");
+                               Assert.IsNotNull (createdKey.GetValue (string.Empty), "#A5");
+                               Assert.AreEqual ("value1", createdKey.GetValue (string.Empty), "#A6");
+                               Assert.IsNotNull (createdKey.GetValue (null), "#A7");
+                               Assert.AreEqual ("value1", createdKey.GetValue (null), "#A8");
+
+                               createdKey.SetValue (null, "value2");
+                               names = createdKey.GetValueNames ();
+                               Assert.IsNotNull (names, "#B1");
+                               Assert.AreEqual (1, names.Length, "#B2");
+                               Assert.IsNotNull (names [0], "#B3");
+                               Assert.AreEqual (string.Empty, names [0], "#B4");
+                               Assert.IsNotNull (createdKey.GetValue (string.Empty), "#B5");
+                               Assert.AreEqual ("value2", createdKey.GetValue (string.Empty), "#B6");
+                               Assert.IsNotNull (createdKey.GetValue (null), "#B7");
+                               Assert.AreEqual ("value2", createdKey.GetValue (null), "#B8");
+                       } finally {
+                               // clean-up
+                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                       }
+               }
+
                [Test]
                [ExpectedException (typeof (ArgumentNullException))]
                public void SetValue_Null ()
@@ -338,5 +1529,484 @@ namespace MonoTests.Microsoft.Win32
                                Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
                        }
                }
+
+               [Test]
+               public void SetValue_Key_ReadOnly ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software")) {
+                               try {
+                                       softwareKey.SetValue ("name1", "value1");
+                                       Assert.Fail ("#1");
+                               } catch (UnauthorizedAccessException ex) {
+                                       // Cannot write to the registry key
+                                       Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#2");
+                                       Assert.IsNotNull (ex.Message, "#3");
+                                       Assert.IsNull (ex.InnerException, "#4");
+                               }
+                       }
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       using (RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName)) {
+                                       }
+
+                                       using (RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName)) {
+                                               try {
+                                                       createdKey.SetValue ("name1", "value1");
+                                                       Assert.Fail ("#1");
+                                               } catch (UnauthorizedAccessException ex) {
+                                                       // Cannot write to the registry key.
+                                                       Assert.AreEqual (typeof (UnauthorizedAccessException), ex.GetType (), "#2");
+                                                       Assert.IsNotNull (ex.Message, "#3");
+                                                       Assert.IsNull (ex.InnerException, "#4");
+                                               }
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void SetValue_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       using (RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName)) {
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                               Assert.IsNull (softwareKey.OpenSubKey (subKeyName), "#1");
+                                               try {
+                                                       createdKey.SetValue ("name1", "value1");
+                                                       Assert.Fail ("#2");
+                                               } catch (IOException ex) {
+                                                       // Illegal operation attempted on a registry key that
+                                                       // has been marked for deletion
+                                                       Assert.AreEqual (typeof (IOException), ex.GetType (), "#3");
+                                                       Assert.IsNotNull (ex.Message, "#4");
+                                                       Assert.IsNull (ex.InnerException, "#5");
+                                               }
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void SubKeyCount ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#A1");
+                                       using (RegistryKey subKey = createdKey.CreateSubKey ("monotemp1")) {
+                                               subKey.Close ();
+                                       }
+                                       Assert.AreEqual (1, createdKey.SubKeyCount, "#A2");
+                                       using (RegistryKey subKey = createdKey.CreateSubKey ("monotemp2")) {
+                                               subKey.Close ();
+                                       }
+                                       Assert.AreEqual (2, createdKey.SubKeyCount, "#A3");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey, "#B1");
+                                       Assert.AreEqual (2, createdKey.SubKeyCount, "#B2");
+
+                                       using (RegistryKey createdKey2 = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                               Assert.IsNotNull (createdKey2, "#B3");
+                                               Assert.AreEqual (2, createdKey2.SubKeyCount, "#B4");
+                                               createdKey2.DeleteSubKey ("monotemp1");
+                                               Assert.AreEqual (1, createdKey2.SubKeyCount, "#B5");
+                                       }
+                                       Assert.AreEqual (1, createdKey.SubKeyCount, "#B6");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void SubKeyCount_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#A1");
+                                       using (RegistryKey subKey = createdKey.CreateSubKey ("monotemp1")) {
+                                               subKey.Close ();
+                                       }
+                                       Assert.AreEqual (1, createdKey.SubKeyCount, "#A2");
+                                       using (RegistryKey subKey = createdKey.CreateSubKey ("monotemp2")) {
+                                               subKey.Close ();
+                                       }
+                                       Assert.AreEqual (2, createdKey.SubKeyCount, "#A3");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey, "#B1");
+                                       Assert.AreEqual (2, createdKey.SubKeyCount, "#B2");
+
+                                       // remove created key
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+
+                                       try {
+                                               Assert.Fail ("#C1: " + createdKey.SubKeyCount);
+                                       } catch (IOException ex) {
+                                               // Illegal operation attempted on a registry key that
+                                               // has been marked for deletion
+                                               Assert.AreEqual (typeof (IOException), ex.GetType (), "#14");
+                                               Assert.IsNotNull (ex.Message, "#15");
+                                               Assert.IsNull (ex.InnerException, "#16");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void ValueCount ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#A1");
+                                       Assert.AreEqual (0, createdKey.ValueCount, "#A2");
+                                       createdKey.SetValue ("name1", "value1");
+                                       Assert.AreEqual (1, createdKey.ValueCount, "#A3");
+                                       createdKey.SetValue ("name2", "value2");
+                                       Assert.AreEqual (2, createdKey.ValueCount, "#A4");
+                                       createdKey.SetValue ("name2", "value2b");
+                                       Assert.AreEqual (2, createdKey.ValueCount, "#A5");
+                                       createdKey.SetValue ("name3", "value3");
+                                       Assert.AreEqual (3, createdKey.ValueCount, "#A6");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey, "#B1");
+                                       Assert.AreEqual (3, createdKey.ValueCount, "#B2");
+
+                                       using (RegistryKey createdKey2 = Registry.CurrentUser.OpenSubKey (subKeyName, true)) {
+                                               Assert.IsNotNull (createdKey2, "#B3");
+                                               Assert.AreEqual (3, createdKey2.ValueCount, "#B4");
+                                               createdKey2.DeleteValue ("name2");
+                                               Assert.AreEqual (2, createdKey2.ValueCount, "#B5");
+                                       }
+                                       Assert.AreEqual (2, createdKey.ValueCount, "#B6");
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void ValueCount_Key_Removed ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       // check if key was successfully created
+                                       Assert.IsNotNull (createdKey, "#A1");
+                                       Assert.AreEqual (0, createdKey.ValueCount, "#A2");
+                                       createdKey.SetValue ("name1", "value1");
+                                       Assert.AreEqual (1, createdKey.ValueCount, "#A3");
+                                       createdKey.SetValue ("name2", "value2");
+                                       Assert.AreEqual (2, createdKey.ValueCount, "#A4");
+                                       createdKey.SetValue ("name2", "value2b");
+                                       Assert.AreEqual (2, createdKey.ValueCount, "#A5");
+                                       createdKey.SetValue ("name3", "value3");
+                                       Assert.AreEqual (3, createdKey.ValueCount, "#A6");
+                               }
+                               using (RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName)) {
+                                       Assert.IsNotNull (createdKey, "#B1");
+                                       Assert.AreEqual (3, createdKey.ValueCount, "#B2");
+
+                                       // remove created key
+                                       Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+
+                                       try {
+                                               Assert.Fail ("#C1: " + createdKey.ValueCount);
+                                       } catch (IOException ex) {
+                                               // Illegal operation attempted on a registry key that
+                                               // has been marked for deletion
+                                               Assert.AreEqual (typeof (IOException), ex.GetType (), "#14");
+                                               Assert.IsNotNull (ex.Message, "#15");
+                                               Assert.IsNull (ex.InnerException, "#16");
+                                       }
+                               }
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void bug79051 ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       using (RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName)) {
+                                               createdKey.SetValue ("test", "whatever");
+                                               createdKey.Close ();
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void bug79059 ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       using (RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName)) {
+                                               using (RegistryKey softwareKey2 = Registry.CurrentUser.OpenSubKey ("software")) {
+                                               }
+                                               createdKey.Close ();
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void bugnew1 ()
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       using (RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey ("software", true)) {
+                               try {
+                                       using (RegistryKey createdKey = softwareKey.CreateSubKey (subKeyName)) {
+                                               createdKey.SetValue ("name1", "value1");
+
+                                               RegistryKey testKey = null;
+                                               try {
+                                                       testKey = createdKey.OpenSubKey ("test", true);
+                                                       if (testKey == null)
+                                                               testKey = createdKey.CreateSubKey ("test");
+                                                       testKey.SetValue ("another", "one");
+                                               } finally {
+                                                       if (testKey != null)
+                                                               testKey.Close ();
+                                               }
+
+                                               createdKey.SetValue ("name2", "value2");
+                                               Assert.IsNotNull (createdKey.GetValue ("name1"), "#2");
+                                               Assert.AreEqual ("value1", createdKey.GetValue ("name1"), "#3");
+                                               Assert.IsNotNull (createdKey.GetValue ("name2"), "#4");
+                                               Assert.AreEqual ("value2", createdKey.GetValue ("name2"), "#5");
+
+                                               string [] names = createdKey.GetValueNames ();
+                                               Assert.IsNotNull (names, "#6");
+                                               Assert.AreEqual (2, names.Length, "#7");
+                                               Assert.AreEqual ("name1", names [0], "#8");
+                                               Assert.AreEqual ("name2", names [1], "#9");
+
+                                               softwareKey.DeleteSubKeyTree (subKeyName);
+
+                                               using (RegistryKey openedKey = softwareKey.OpenSubKey (subKeyName, true)) {
+                                                       Assert.IsNull (openedKey, "#10");
+                                               }
+
+                                               Assert.IsNull (createdKey.GetValue ("name1"), "#11");
+                                               Assert.IsNull (createdKey.GetValue ("name2"), "#12");
+
+                                               try {
+                                                       createdKey.GetValueNames ();
+                                                       Assert.Fail ("#13");
+                                               } catch (IOException ex) {
+                                                       // Illegal operation attempted on a registry key that
+                                                       // has been marked for deletion
+                                                       Assert.AreEqual (typeof (IOException), ex.GetType (), "#14");
+                                                       Assert.IsNotNull (ex.Message, "#15");
+                                                       Assert.IsNull (ex.InnerException, "#16");
+                                               }
+
+                                               try {
+                                                       createdKey.SetValue ("name1", "value1");
+                                                       Assert.Fail ("#17");
+                                               } catch (IOException ex) {
+                                                       // Illegal operation attempted on a registry key that
+                                                       // has been marked for deletion
+                                                       Assert.AreEqual (typeof (IOException), ex.GetType (), "#18");
+                                                       Assert.IsNotNull (ex.Message, "#19");
+                                                       Assert.IsNull (ex.InnerException, "#20");
+                                               }
+
+                                               try {
+                                                       createdKey.SetValue ("newname", "value1");
+                                                       Assert.Fail ("#21");
+                                               } catch (IOException ex) {
+                                                       // Illegal operation attempted on a registry key that
+                                                       // has been marked for deletion
+                                                       Assert.AreEqual (typeof (IOException), ex.GetType (), "#22");
+                                                       Assert.IsNotNull (ex.Message, "#23");
+                                                       Assert.IsNull (ex.InnerException, "#24");
+                                               }
+
+                                               Assert.IsNull (createdKey.OpenSubKey ("test"), "#25");
+                                               Assert.IsNull (createdKey.OpenSubKey ("test", true), "#26");
+                                               Assert.IsNull (createdKey.OpenSubKey ("new"), "#27");
+                                               Assert.IsNull (createdKey.OpenSubKey ("new", true), "#28");
+
+                                               try {
+                                                       createdKey.CreateSubKey ("new");
+                                                       Assert.Fail ("#29");
+                                               } catch (IOException ex) {
+                                                       // Illegal operation attempted on a registry key that
+                                                       // has been marked for deletion
+                                                       Assert.AreEqual (typeof (IOException), ex.GetType (), "#30");
+                                                       Assert.IsNotNull (ex.Message, "#31");
+                                                       Assert.IsNull (ex.InnerException, "#32");
+                                               }
+                                       }
+                               } finally {
+                                       try {
+                                               RegistryKey createdKey = softwareKey.OpenSubKey (subKeyName);
+                                               if (createdKey != null) {
+                                                       createdKey.Close ();
+                                                       softwareKey.DeleteSubKeyTree (subKeyName);
+                                               }
+                                       } catch {
+                                       }
+                               }
+                       }
+               }
+
+               [Test]
+               public void bugnew2 () // values cannot be written on registry root (hive)
+               {
+                       string [] names = Registry.CurrentUser.GetValueNames ();
+                       Assert.IsNotNull (names, "#1");
+                       Registry.CurrentUser.SetValue ("name1", "value1");
+                       Assert.IsNotNull (Registry.CurrentUser.GetValue ("name1"), "#2");
+                       Assert.AreEqual ("value1", Registry.CurrentUser.GetValue ("name1"), "#3");
+                       string [] newNames = Registry.CurrentUser.GetValueNames ();
+                       Assert.IsNotNull (newNames, "#4");
+                       Assert.AreEqual (names.Length + 1, newNames.Length, "#5");
+                       Registry.CurrentUser.DeleteValue ("name1");
+               }
+
+               [Test]
+               public void bugnew3 () // on Windows, key cannot be closed twice
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.Close ();
+                               }
+
+                               RegistryKey openedKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                               openedKey.Close ();
+                               openedKey.Close ();
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
+
+               [Test]
+               public void bugnew4 () // Key cannot be flushed once it has been closed
+               {
+                       string subKeyName = Guid.NewGuid ().ToString ();
+
+                       try {
+                               using (RegistryKey createdKey = Registry.CurrentUser.CreateSubKey (subKeyName)) {
+                                       createdKey.Close ();
+                               }
+
+                               RegistryKey openedKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                               openedKey.Close ();
+                               openedKey.Flush ();
+                       } finally {
+                               try {
+                                       RegistryKey createdKey = Registry.CurrentUser.OpenSubKey (subKeyName);
+                                       if (createdKey != null) {
+                                               createdKey.Close ();
+                                               Registry.CurrentUser.DeleteSubKeyTree (subKeyName);
+                                       }
+                               } catch {
+                               }
+                       }
+               }
        }
 }