[runtime] Don't consume exception if not allowed to
[mono.git] / mcs / class / corlib / Microsoft.Win32 / RegistryKey.cs
1 //
2 // RegistryKey.cs: a single node in the Windows registry
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Erik LeBel (eriklebel@yahoo.ca)
7 //   Gert Driesen (drieseng@users.sourceforge.net)
8 //
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.IO;
34 using System.Collections;
35 using System.Diagnostics;
36 using System.Runtime.InteropServices;
37 using System.Security;
38 using System.Text;
39 using System.Security.AccessControl;
40 using System.Security.Permissions;
41 using Microsoft.Win32.SafeHandles;
42
43 namespace Microsoft.Win32
44 {
45
46 #if MOBILE && !WIN_PLATFORM
47         public sealed class RegistryKey : IDisposable
48         {
49                 internal RegistryKey (RegistryHive hiveId)
50                 {
51                         throw new PlatformNotSupportedException ();
52                 }
53
54                 public void Dispose ()
55                 {
56                 }
57
58                 public RegistryKey CreateSubKey (string subkey)
59                 {
60                         throw new PlatformNotSupportedException ();
61                 }
62
63                 public RegistryKey CreateSubKey (String subkey, bool writable)
64                 {
65                         throw new PlatformNotSupportedException ();
66                 }
67
68                 public RegistryKey CreateSubKey (String subkey, bool writable, RegistryOptions options)
69                 {
70                         throw new PlatformNotSupportedException ();
71                 }
72
73                 public void DeleteSubKey (string subkey)
74                 {
75                 }
76
77                 public void DeleteSubKey (string subkey, bool throwOnMissingSubKey)
78                 {
79                 }
80
81                 public void DeleteSubKeyTree (string subkey)
82                 {
83                 }
84
85                 public void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
86                 {
87                 }
88
89                 public void DeleteValue (string name)
90                 {
91                 }
92
93                 public void DeleteValue (string name, bool throwOnMissingValue)
94                 {
95                 }
96
97                 public void Flush()
98                 {
99                 }
100
101                 public static RegistryKey FromHandle (SafeRegistryHandle handle)
102                 {
103                         throw new PlatformNotSupportedException ();
104                 }
105
106                 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
107                 {
108                         throw new PlatformNotSupportedException ();
109                 }
110
111                 public string[] GetSubKeyNames ()
112                 {
113                         throw new PlatformNotSupportedException ();
114                 }
115
116                 public object GetValue (string name)
117                 {
118                         throw new PlatformNotSupportedException ();
119                 }
120
121                 public object GetValue (string name, object defaultValue)
122                 {
123                         throw new PlatformNotSupportedException ();
124                 }
125
126                 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
127                 {
128                         throw new PlatformNotSupportedException ();
129                 }
130
131                 public RegistryValueKind GetValueKind (string name)
132                 {
133                         throw new PlatformNotSupportedException ();
134                 }
135
136                 public string[] GetValueNames ()
137                 {
138                         throw new PlatformNotSupportedException ();
139                 }
140
141                 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
142                 {
143                         throw new PlatformNotSupportedException ();
144                 }
145
146                 public RegistryKey OpenSubKey (string name)
147                 {
148                         throw new PlatformNotSupportedException ();
149                 }
150
151                 public RegistryKey OpenSubKey (string name, bool writable)
152                 {
153                         throw new PlatformNotSupportedException ();
154                 }
155
156                 public RegistryKey OpenSubKey (string name, RegistryRights rights)
157                 {
158                         throw new PlatformNotSupportedException ();
159                 }
160
161                 public void SetValue (string name, object value)
162                 {
163                 }
164
165                 public void SetValue (string name, object value, RegistryValueKind valueKind)
166                 {
167                 }
168
169                 public SafeRegistryHandle Handle {
170                         get { throw new PlatformNotSupportedException (); }
171                 }
172
173                 public string Name {
174                         get { throw new PlatformNotSupportedException (); }
175                 }
176
177                 public int SubKeyCount {
178                         get { throw new PlatformNotSupportedException (); }
179                 }
180
181                 public int ValueCount {
182                         get { throw new PlatformNotSupportedException (); }
183                 }
184
185                 public RegistryView View {
186                         get { throw new PlatformNotSupportedException (); }
187                 }
188         }
189 #else
190         /// <summary>
191         ///     Wrapper class for Windows Registry Entry.
192         /// </summary>
193         [ComVisible (true)]
194         public sealed class RegistryKey : MarshalByRefObject, IDisposable 
195         {
196                 //
197                 // This represents the backend data, used when creating the
198                 // RegistryKey object
199                 //
200                 object handle;
201                 SafeRegistryHandle safe_handle;
202
203                 object hive; // the RegistryHive if the key represents a base key
204                 readonly string qname;  // the fully qualified registry key name
205                 readonly bool isRemoteRoot;     // is an instance of a remote root key?
206                 readonly bool isWritable;       // is the key openen in writable mode
207
208                 static readonly IRegistryApi RegistryApi;
209
210                 static RegistryKey ()
211                 {
212 #if !XAMMAC_4_5
213                         if (Path.DirectorySeparatorChar == '\\')
214                                 RegistryApi = new Win32RegistryApi ();
215                         else
216 #endif
217                                 RegistryApi = new UnixRegistryApi ();
218                 }
219
220                 /// <summary>
221                 ///     Construct an instance of a root registry key entry.
222                 /// </summary>
223                 internal RegistryKey (RegistryHive hiveId) : this (hiveId, 
224                         new IntPtr ((int) hiveId), false)
225                 {
226                 }
227
228                 /// <summary>
229                 ///     Construct an instance of a root registry key entry.
230                 /// </summary>
231                 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
232                 {
233                         hive = hiveId;
234                         handle = keyHandle;
235                         qname = GetHiveName (hiveId);
236                         isRemoteRoot = remoteRoot;
237                         isWritable = true; // always consider root writable
238                 }
239
240                 /// <summary>
241                 ///     Construct an instance of a registry key entry.
242                 /// </summary>
243                 internal RegistryKey (object data, string keyName, bool writable)
244                 {
245                         handle = data;
246                         qname = keyName;
247                         isWritable = writable;
248                 }
249
250                 static internal bool IsEquals (RegistryKey a, RegistryKey b)
251                 {
252                         return a.hive == b.hive && a.handle == b.handle && a.qname == b.qname  && a.isRemoteRoot == b.isRemoteRoot && a.isWritable == b.isWritable;
253                 }
254
255                 #region PublicAPI
256
257                 /// <summary>
258                 ///     Dispose of registry key object. Close the 
259                 ///     key if it's still open.
260                 /// </summary>
261                 public void Dispose ()
262                 {
263                         GC.SuppressFinalize (this);
264                         Close ();
265                 }
266
267                 /// <summary>
268                 ///     Get the fully qualified registry key name.
269                 /// </summary>
270                 public string Name {
271                         get { return qname; }
272                 }
273         
274                 
275                 /// <summary>
276                 ///     Flush the current registry state to disk.
277                 /// </summary>
278                 public void Flush()
279                 {
280                         RegistryApi.Flush (this);
281                 }
282                 
283                 
284                 /// <summary>
285                 ///     Close the current registry key and flushes the state of the registry
286                 /// right away.
287                 /// </summary>
288                 public void Close()
289                 {
290                         Flush ();
291
292                         // a handle to a remote hive must be closed, while one to a local
293                         // hive should not be closed
294                         if (!isRemoteRoot && IsRoot)
295                                 return;
296                         
297                         RegistryApi.Close (this);
298                         handle = null;
299                         safe_handle = null;
300                 }
301                 
302                 
303                 /// <summary>
304                 ///     get the number of sub-keys for this key
305                 /// </summary>
306                 public int SubKeyCount {
307                         get {
308                                 AssertKeyStillValid ();
309
310                                 return RegistryApi.SubKeyCount (this);
311                         }
312                 }
313
314                 
315                 /// <summary>
316                 ///     get the number of values for this key
317                 /// </summary>
318                 public int ValueCount {
319                         get {
320                                 AssertKeyStillValid ();
321
322                                 return RegistryApi.ValueCount (this);
323                         }
324                 }
325
326                 [ComVisible (false)]
327                 [MonoTODO ("Not implemented in Unix")]
328                 public SafeRegistryHandle Handle {
329                         get {
330                                 AssertKeyStillValid ();
331
332                                 if (safe_handle == null) {
333                                         IntPtr h = RegistryApi.GetHandle (this);
334                                         safe_handle = new SafeRegistryHandle (h, true);
335                                 }
336
337                                 return safe_handle;
338                         }
339                 }
340
341                 [ComVisible (false)]
342                 [MonoLimitation ("View is ignored in Mono.")]
343                 public RegistryView View {
344                         get {
345                                 return RegistryView.Default;
346                         }
347                 }
348
349                 
350                 /// <summary>
351                 ///     Set a registry value.
352                 /// </summary>
353                 public void SetValue (string name, object value)
354                 {
355                         AssertKeyStillValid ();
356
357                         if (value == null)
358                                 throw new ArgumentNullException ("value");
359
360                         if (name != null)
361                                 AssertKeyNameLength (name);
362
363                         if (!IsWritable)
364                                 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
365
366                         RegistryApi.SetValue (this, name, value);
367                 }
368
369                 [ComVisible (false)]
370                 public void SetValue (string name, object value, RegistryValueKind valueKind)
371                 {
372                         AssertKeyStillValid ();
373                         
374                         if (value == null)
375                                 throw new ArgumentNullException ("value");
376
377                         if (name != null)
378                                 AssertKeyNameLength (name);
379
380                         if (!IsWritable)
381                                 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
382
383                         RegistryApi.SetValue (this, name, value, valueKind);
384                 }
385
386                 /// <summary>
387                 ///     Open the sub key specified, for read access.
388                 /// </summary>
389                 public RegistryKey OpenSubKey (string name)
390                 {
391                         return OpenSubKey (name, false);
392                 }
393
394                 
395                 /// <summary>
396                 ///     Open the sub key specified.
397                 /// </summary>
398                 public RegistryKey OpenSubKey (string name, bool writable)
399                 {
400                         AssertKeyStillValid ();
401
402                         if (name == null)
403                                 throw new ArgumentNullException ("name");
404
405                         AssertKeyNameLength (name);
406
407                         return RegistryApi.OpenSubKey (this, name, writable);
408                 }
409                 
410                 
411                 /// <summary>
412                 ///     Get a registry value.
413                 /// </summary>
414                 public object GetValue (string name)
415                 {
416                         return GetValue (name, null);
417                 }
418
419                 
420                 /// <summary>
421                 ///     Get a registry value.
422                 /// </summary>
423                 public object GetValue (string name, object defaultValue)
424                 {
425                         AssertKeyStillValid ();
426                         
427                         return RegistryApi.GetValue (this, name, defaultValue,
428                                 RegistryValueOptions.None);
429                 }
430
431                 [ComVisible (false)]
432                 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
433                 {
434                         AssertKeyStillValid ();
435
436                         return RegistryApi.GetValue (this, name, defaultValue, options);
437                 }
438
439                 [ComVisible (false)]
440                 public RegistryValueKind GetValueKind (string name)
441                 {
442                         return RegistryApi.GetValueKind (this, name);
443                 }
444
445                 /// <summary>
446                 ///     Create a sub key.
447                 /// </summary>
448                 public RegistryKey CreateSubKey (string subkey)
449                 {
450                         AssertKeyStillValid ();
451                         AssertKeyNameNotNull (subkey);
452                         AssertKeyNameLength (subkey);
453
454                         if (!IsWritable)
455                                 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
456                         return RegistryApi.CreateSubKey (this, subkey);
457                 }
458
459                 [ComVisible (false)]
460                 [MonoLimitation ("permissionCheck is ignored in Mono")]
461                 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
462                 {
463                         return CreateSubKey (subkey);
464                 }
465
466                 [ComVisible (false)]
467                 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
468                 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
469                 {
470                         return CreateSubKey (subkey);
471                 }
472
473                 [ComVisible (false)]
474                 [MonoLimitation ("permissionCheck is ignored in Mono")]
475                 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
476                 {
477                         AssertKeyStillValid ();
478                         AssertKeyNameNotNull (subkey);
479                         AssertKeyNameLength (subkey);
480
481                         if (!IsWritable)
482                                 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
483
484                         return RegistryApi.CreateSubKey (this, subkey, options);
485                 }
486
487                 [ComVisible (false)]
488                 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
489                 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions,
490                         RegistrySecurity registrySecurity)
491                 {
492                         return CreateSubKey (subkey, permissionCheck, registryOptions);
493                 }
494
495                 [ComVisible(false)]
496                 public RegistryKey CreateSubKey (string subkey, bool writable)
497                 {
498                         return CreateSubKey (subkey, writable ? RegistryKeyPermissionCheck.ReadWriteSubTree : RegistryKeyPermissionCheck.ReadSubTree);
499                 }
500
501                 [ComVisible(false)]
502                 public RegistryKey CreateSubKey (string subkey, bool writable, RegistryOptions options)
503                 {
504                         return CreateSubKey (subkey, writable ? RegistryKeyPermissionCheck.ReadWriteSubTree : RegistryKeyPermissionCheck.ReadSubTree, options);
505                 }
506
507                 /// <summary>
508                 ///     Delete the specified subkey.
509                 /// </summary>
510                 public void DeleteSubKey(string subkey)
511                 {
512                         DeleteSubKey (subkey, true);
513                 }
514                 
515                 
516                 /// <summary>
517                 ///     Delete the specified subkey.
518                 /// </summary>
519                 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
520                 {
521                         AssertKeyStillValid ();
522                         AssertKeyNameNotNull (subkey);
523                         AssertKeyNameLength (subkey);
524
525                         if (!IsWritable)
526                                 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
527
528                         RegistryKey child = OpenSubKey (subkey);
529                         
530                         if (child == null) {
531                                 if (throwOnMissingSubKey)
532                                         throw new ArgumentException ("Cannot delete a subkey tree"
533                                                 + " because the subkey does not exist.");
534                                 return;
535                         }
536
537                         if (child.SubKeyCount > 0){
538                                 throw new InvalidOperationException ("Registry key has subkeys"
539                                         + " and recursive removes are not supported by this method.");
540                         }
541                         
542                         child.Close ();
543
544                         RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
545                 }
546                 
547                 
548                 /// <summary>
549                 ///     Delete a sub tree (node, and values alike).
550                 /// </summary>
551                 public void DeleteSubKeyTree(string subkey)
552                 {
553                         DeleteSubKeyTree (subkey, true);
554                 }
555
556                 public
557                 void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
558                 {
559                         // Note: this is done by deleting sub-nodes recursively.
560                         // The preformance is not very good. There may be a 
561                         // better way to implement this.
562                         
563                         AssertKeyStillValid ();
564                         AssertKeyNameNotNull (subkey);
565                         AssertKeyNameLength (subkey);
566                         
567                         RegistryKey child = OpenSubKey (subkey, true);
568                         if (child == null) {
569                                 if (!throwOnMissingSubKey)
570                                         return;
571
572                                 throw new ArgumentException ("Cannot delete a subkey tree"
573                                         + " because the subkey does not exist.");
574                         }
575
576                         child.DeleteChildKeysAndValues ();
577                         child.Close ();
578                         DeleteSubKey (subkey, false);
579                 }
580                 
581
582                 /// <summary>
583                 ///     Delete a value from the registry.
584                 /// </summary>
585                 public void DeleteValue(string name)
586                 {
587                         DeleteValue (name, true);
588                 }
589                 
590                 
591                 /// <summary>
592                 ///     Delete a value from the registry.
593                 /// </summary>
594                 public void DeleteValue(string name, bool throwOnMissingValue)
595                 {
596                         AssertKeyStillValid ();
597
598                         if (name == null)
599                                 throw new ArgumentNullException ("name");
600
601                         if (!IsWritable)
602                                 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
603
604                         RegistryApi.DeleteValue (this, name, throwOnMissingValue);
605                 }
606
607                 public RegistrySecurity GetAccessControl ()
608                 {
609                         return GetAccessControl (AccessControlSections.Owner |
610                                                  AccessControlSections.Group |
611                                                  AccessControlSections.Access);
612                 }
613                 
614                 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
615                 {
616                         return new RegistrySecurity (Name, includeSections);
617                 }
618                 
619                 
620                 /// <summary>
621                 ///     Get the names of the sub keys.
622                 /// </summary>
623                 public string[] GetSubKeyNames()
624                 {
625                         AssertKeyStillValid ();
626
627                         return RegistryApi.GetSubKeyNames (this);
628                 }
629                 
630                 
631                 /// <summary>
632                 ///     Get the names of values contained in this key.
633                 /// </summary>
634                 public string[] GetValueNames()
635                 {
636                         AssertKeyStillValid ();
637                         return RegistryApi.GetValueNames (this);
638                 }
639
640                 [ComVisible (false)]
641                 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
642                 [MonoTODO ("Not implemented on unix")]
643                 public static RegistryKey FromHandle (SafeRegistryHandle handle)
644                 {
645                         if (handle == null)
646                                 throw new ArgumentNullException ("handle");
647
648                         return RegistryApi.FromHandle (handle);
649                 }
650
651                 [ComVisible (false)]
652                 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
653                 [MonoTODO ("Not implemented on unix")]
654                 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
655                 {
656                         return FromHandle (handle);
657                 }
658                 
659                 
660                 [MonoTODO ("Not implemented on unix")]
661                 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
662                 {
663                         if (machineName == null)
664                                 throw new ArgumentNullException ("machineName");
665                         return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
666                 }
667
668                 [ComVisible (false)]
669                 [MonoTODO ("Not implemented on unix")]
670                 public static RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName, RegistryView view)
671                 {
672                         if (machineName == null)
673                                 throw new ArgumentNullException ("machineName");
674                         return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
675                 }
676
677                 [ComVisible (false)]
678                 [MonoLimitation ("View is ignored in Mono")]
679                 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
680                 {
681                         switch (hKey) {
682                                 case RegistryHive.ClassesRoot:
683                                         return Registry.ClassesRoot;
684                                 case RegistryHive.CurrentConfig:
685                                         return Registry.CurrentConfig;
686                                 case RegistryHive.CurrentUser:
687                                         return Registry.CurrentUser;
688                                 case RegistryHive.DynData:
689                                         return Registry.DynData;
690                                 case RegistryHive.LocalMachine:
691                                         return Registry.LocalMachine;
692                                 case RegistryHive.PerformanceData:
693                                         return Registry.PerformanceData;
694                                 case RegistryHive.Users:
695                                         return Registry.Users;
696                         }
697
698                         throw new ArgumentException ("hKey");
699                 }
700
701                 [ComVisible (false)]
702                 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
703                 {
704                         return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
705                 }
706
707                 [ComVisible (false)]
708                 [MonoLimitation ("rights are ignored in Mono")]
709                 public RegistryKey OpenSubKey (string name, RegistryRights rights)
710                 {
711                         return OpenSubKey (name);
712                 }
713
714                 [ComVisible (false)]
715                 [MonoLimitation ("rights are ignored in Mono")]
716                 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
717                 {
718                         return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
719                 }
720                 
721                 public void SetAccessControl (RegistrySecurity registrySecurity)
722                 {
723                         if (null == registrySecurity)
724                                 throw new ArgumentNullException ("registrySecurity");
725                                 
726                         registrySecurity.PersistModifications (Name);
727                 }
728                 
729                 
730                 /// <summary>
731                 ///     Build a string representation of the registry key.
732                 ///     Conatins the fully qualified key name, and the Hex
733                 ///     representation of the registry key handle.
734                 /// </summary>
735                 public override string ToString()
736                 {
737                         AssertKeyStillValid ();
738
739                         return RegistryApi.ToString (this);
740                 }
741
742                 #endregion // PublicAPI
743
744                 internal bool IsRoot {
745                         get { return hive != null; }
746                 }
747
748                 private bool IsWritable {
749                         get { return isWritable; }
750                 }
751
752                 internal RegistryHive Hive {
753                         get {
754                                 if (!IsRoot)
755                                         throw new NotSupportedException ();
756                                 return (RegistryHive) hive;
757                         }
758                 }
759
760                 // returns the key handle for the win32 implementation and the
761                 // KeyHandler for the unix implementation
762                 internal object InternalHandle {
763                         get { return handle; }
764                 }
765
766                 /// <summary>
767                 /// validate that the registry key handle is still usable.
768                 /// </summary>
769                 private void AssertKeyStillValid ()
770                 {
771                         if (handle == null)
772                                 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
773                 }
774
775                 
776                 /// <summary>
777                 /// validate that the registry key handle is still usable, and
778                 /// that the 'subKeyName' is not null.
779                 /// </summary>
780                 private void AssertKeyNameNotNull (string subKeyName)
781                 {
782                         if (subKeyName == null)
783                                 throw new ArgumentNullException ("name");
784                 }
785
786                 private void AssertKeyNameLength (string name)
787                 {
788                         if (name.Length > 255)
789                                 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
790                 }
791
792                 /// <summary>
793                 ///     Utility method to delelte a key's sub keys and values.
794                 ///     This method removes a level of indirection when deleting
795                 ///     key node trees.
796                 /// </summary>
797                 private void DeleteChildKeysAndValues ()
798                 {
799                         if (IsRoot)
800                                 return;
801                         
802                         string[] subKeys = GetSubKeyNames ();
803                         foreach (string subKey in subKeys)
804                         {
805                                 RegistryKey sub = OpenSubKey (subKey, true);
806                                 sub.DeleteChildKeysAndValues ();
807                                 sub.Close ();
808                                 DeleteSubKey (subKey, false);
809                         }
810
811                         string[] values = GetValueNames ();
812                         foreach (string value in values) {
813                                 DeleteValue (value, false);
814                         }
815                 }
816
817                 /// <summary>
818                 ///     decode a byte array as a string, and strip trailing nulls
819                 /// </summary>
820                 static internal string DecodeString (byte[] data)
821                 {
822                         string stringRep = Encoding.Unicode.GetString (data);
823                         int idx = stringRep.IndexOf ('\0');
824                         if (idx != -1)
825                                 stringRep = stringRep.TrimEnd ('\0');
826                         return stringRep;
827                 }
828
829                 static internal IOException CreateMarkedForDeletionException ()
830                 {
831                         throw new IOException ("Illegal operation attempted on a"
832                                 + " registry key that has been marked for deletion.");
833                 }
834
835                 static string GetHiveName (RegistryHive hive)
836                 {
837                         switch (hive) {
838                         case RegistryHive.ClassesRoot:
839                                 return "HKEY_CLASSES_ROOT";
840                         case RegistryHive.CurrentConfig:
841                                 return "HKEY_CURRENT_CONFIG";
842                         case RegistryHive.CurrentUser:
843                                 return "HKEY_CURRENT_USER";
844                         case RegistryHive.DynData:
845                                 return "HKEY_DYN_DATA";
846                         case RegistryHive.LocalMachine:
847                                 return "HKEY_LOCAL_MACHINE";
848                         case RegistryHive.PerformanceData:
849                                 return "HKEY_PERFORMANCE_DATA";
850                         case RegistryHive.Users:
851                                 return "HKEY_USERS";
852                         }
853
854                         throw new NotImplementedException (string.Format (
855                                 "Registry hive '{0}' is not implemented.", hive.ToString ()));
856                 }
857
858         }
859 #endif
860 }
861