Implement 4.0 RegistryKey.Handle property.
[mono.git] / mcs / class / corlib / Microsoft.Win32 / Win32RegistryApi.cs
1 //
2 // Microsoft.Win32/Win32RegistryApi.cs: wrapper for win32 registry API
3 //
4 // Authos:
5 //      Erik LeBel (eriklebel@yahoo.ca)
6 //      Jackson Harper (jackson@ximian.com)
7 //      Miguel de Icaza (miguel@gnome.org)
8 //
9 // Copyright (C) Erik LeBel 2004
10 // (C) 2004, 2005 Novell, Inc (http://www.novell.com)
11 // 
12
13 //
14 // Copyright (C) 2004, 2005 Novell, Inc (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 #if !NET_2_1
37
38 using System;
39 using System.Collections;
40 using System.IO;
41 using System.Runtime.InteropServices;
42 using System.Security;
43 using System.Text;
44 using Microsoft.Win32.SafeHandles;
45
46 namespace Microsoft.Win32
47 {
48         /// <summary>
49         ///     Function stubs, constants and helper functions for
50         ///     the Win32 registry manipulation utilities.
51         /// </summary>
52         internal class Win32RegistryApi : IRegistryApi
53         {
54                 // bit masks for registry key open access permissions
55                 const int OpenRegKeyRead = 0x00020019; 
56                 const int OpenRegKeyWrite = 0x00020006; 
57
58                 // FIXME must be a way to determin this dynamically?
59                 const int Int32ByteSize = 4;
60
61                 // FIXME this is hard coded on Mono, can it be determined dynamically? 
62                 readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
63
64                 const int RegOptionsNonVolatile = 0x00000000;
65                 const int RegOptionsVolatile = 0x00000001;
66
67                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKeyEx")]
68                 static extern int RegCreateKeyEx (IntPtr keyBase, string keyName, int reserved, 
69                         IntPtr lpClass, int options, int access, IntPtr securityAttrs,
70                         out IntPtr keyHandle, out int disposition);
71                
72                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
73                 static extern int RegCloseKey (IntPtr keyHandle);
74
75                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
76                 static extern int RegConnectRegistry (string machineName, IntPtr hKey,
77                                 out IntPtr keyHandle);
78
79                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
80                 private static extern int RegFlushKey (IntPtr keyHandle);
81
82                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
83                 private static extern int RegOpenKeyEx (IntPtr keyBase,
84                                 string keyName, IntPtr reserved, int access,
85                                 out IntPtr keyHandle);
86
87                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
88                 private static extern int RegDeleteKey (IntPtr keyHandle, string valueName);
89
90                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
91                 private static extern int RegDeleteValue (IntPtr keyHandle, string valueName);
92
93                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
94                 private static extern int RegEnumKey (IntPtr keyBase, int index, StringBuilder nameBuffer, int bufferLength);
95
96                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
97                 private static extern int RegEnumValue (IntPtr keyBase, 
98                                 int index, StringBuilder nameBuffer, 
99                                 ref int nameLength, IntPtr reserved, 
100                                 ref RegistryValueKind type, IntPtr data, IntPtr dataLength);
101
102 //              [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
103 //              private static extern int RegSetValueEx (IntPtr keyBase, 
104 //                              string valueName, IntPtr reserved, RegistryValueKind type,
105 //                              StringBuilder data, int rawDataLength);
106
107                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
108                 private static extern int RegSetValueEx (IntPtr keyBase, 
109                                 string valueName, IntPtr reserved, RegistryValueKind type,
110                                 string data, int rawDataLength);
111
112                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
113                 private static extern int RegSetValueEx (IntPtr keyBase, 
114                                 string valueName, IntPtr reserved, RegistryValueKind type,
115                                 byte[] rawData, int rawDataLength);
116
117                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
118                 private static extern int RegSetValueEx (IntPtr keyBase, 
119                                 string valueName, IntPtr reserved, RegistryValueKind type,
120                                 ref int data, int rawDataLength);
121
122                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
123                 private static extern int RegQueryValueEx (IntPtr keyBase,
124                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
125                                 IntPtr zero, ref int dataSize);
126
127                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
128                 private static extern int RegQueryValueEx (IntPtr keyBase,
129                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
130                                 [Out] byte[] data, ref int dataSize);
131
132                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
133                 private static extern int RegQueryValueEx (IntPtr keyBase,
134                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
135                                 ref int data, ref int dataSize);
136
137                 // Returns our handle from the RegistryKey
138                 public IntPtr GetHandle (RegistryKey key)
139                 {
140                         return (IntPtr) key.InternalHandle;
141                 }
142
143                 static bool IsHandleValid (RegistryKey key)
144                 {
145                         return key.InternalHandle != null;
146                 }
147
148                 public RegistryValueKind GetValueKind (RegistryKey rkey, string name)
149                 {
150                         RegistryValueKind type = 0;
151                         int size = 0;
152                         IntPtr handle = GetHandle (rkey);
153                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
154
155                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) 
156                                 return RegistryValueKind.Unknown;
157
158                         return type;
159                 }
160                 
161                 /// <summary>
162                 /// Acctually read a registry value. Requires knowledge of the
163                 /// value's type and size.
164                 /// </summary>
165                 public object GetValue (RegistryKey rkey, string name, object defaultValue, RegistryValueOptions options)
166                 {
167                         RegistryValueKind type = 0;
168                         int size = 0;
169                         object obj = null;
170                         IntPtr handle = GetHandle (rkey);
171                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
172
173                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) {
174                                 return defaultValue;
175                         }
176                         
177                         if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success ) {
178                                 GenerateException (result);
179                         }
180                         
181                         if (type == RegistryValueKind.String) {
182                                 byte[] data;
183                                 result = GetBinaryValue (rkey, name, type, out data, size);
184                                 obj = RegistryKey.DecodeString (data);
185                         } else if (type == RegistryValueKind.ExpandString) {
186                                 byte [] data;
187                                 result = GetBinaryValue (rkey, name, type, out data, size);
188                                 obj = RegistryKey.DecodeString (data);
189                                 if ((options & RegistryValueOptions.DoNotExpandEnvironmentNames) == 0)
190                                         obj = Environment.ExpandEnvironmentVariables ((string) obj);
191                         } else if (type == RegistryValueKind.DWord) {
192                                 int data = 0;
193                                 result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
194                                 obj = data;
195                         } else if (type == RegistryValueKind.Binary) {
196                                 byte[] data;
197                                 result = GetBinaryValue (rkey, name, type, out data, size);
198                                 obj = data;
199                         } else if (type == RegistryValueKind.MultiString) {
200                                 obj = null;
201                                 byte[] data;
202                                 result = GetBinaryValue (rkey, name, type, out data, size);
203                                 
204                                 if (result == Win32ResultCode.Success)
205                                         obj = RegistryKey.DecodeString (data).Split ('\0');
206                         } else {
207                                 // should never get here
208                                 throw new SystemException ();
209                         }
210
211                         // check result codes again:
212                         if (result != Win32ResultCode.Success)
213                         {
214                                 GenerateException (result);
215                         }
216                         
217
218                         return obj;
219                 }
220
221                 //
222                 // This version has to do extra checking, make sure that the requested
223                 // valueKind matches the type of the value being stored
224                 //
225                 public void SetValue (RegistryKey rkey, string name, object value, RegistryValueKind valueKind)
226                 {
227                         Type type = value.GetType ();
228                         int result;
229                         IntPtr handle = GetHandle (rkey);
230
231                         if (valueKind == RegistryValueKind.DWord && type == typeof (int)) {
232                                 int rawValue = (int)value;
233                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize); 
234                         } else if (valueKind == RegistryValueKind.Binary && type == typeof (byte[])) {
235                                 byte[] rawValue = (byte[]) value;
236                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
237                         } else if (valueKind == RegistryValueKind.MultiString && type == typeof (string[])) {
238                                 string[] vals = (string[]) value;
239                                 StringBuilder fullStringValue = new StringBuilder ();
240                                 foreach (string v in vals)
241                                 {
242                                         fullStringValue.Append (v);
243                                         fullStringValue.Append ('\0');
244                                 }
245                                 fullStringValue.Append ('\0');
246
247                                 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
248                         
249                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length); 
250                         } else if ((valueKind == RegistryValueKind.String || valueKind == RegistryValueKind.ExpandString) &&
251                                    type == typeof (string)){
252                                 string rawValue = String.Format ("{0}{1}", value, '\0');
253                                 result = RegSetValueEx (handle, name, IntPtr.Zero, valueKind, rawValue,
254                                                         rawValue.Length * NativeBytesPerCharacter);
255                                 
256                         } else if (type.IsArray) {
257                                 throw new ArgumentException ("Only string and byte arrays can written as registry values");
258                         } else {
259                                 throw new ArgumentException ("Type does not match the valueKind");
260                         }
261
262                         // handle the result codes
263                         if (result != Win32ResultCode.Success)
264                         {
265                                 GenerateException (result);
266                         }
267                 }
268         
269                 public void SetValue (RegistryKey rkey, string name, object value)
270                 {
271                         Type type = value.GetType ();
272                         int result;
273                         IntPtr handle = GetHandle (rkey);
274
275                         if (type == typeof (int)) {
276                                 int rawValue = (int)value;
277                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize); 
278                         } else if (type == typeof (byte[])) {
279                                 byte[] rawValue = (byte[]) value;
280                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
281                         } else if (type == typeof (string[])) {
282                                 string[] vals = (string[]) value;
283                                 StringBuilder fullStringValue = new StringBuilder ();
284                                 foreach (string v in vals)
285                                 {
286                                         fullStringValue.Append (v);
287                                         fullStringValue.Append ('\0');
288                                 }
289                                 fullStringValue.Append ('\0');
290
291                                 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
292                         
293                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length); 
294                         } else if (type.IsArray) {
295                                 throw new ArgumentException ("Only string and byte arrays can written as registry values");
296                         } else {
297                                 string rawValue = String.Format ("{0}{1}", value, '\0');
298                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.String, rawValue,
299                                                         rawValue.Length * NativeBytesPerCharacter);
300                         }
301
302                         if (result == Win32ResultCode.MarkedForDeletion)
303                                 throw RegistryKey.CreateMarkedForDeletionException ();
304
305                         // handle the result codes
306                         if (result != Win32ResultCode.Success)
307                         {
308                                 GenerateException (result);
309                         }
310                 }
311
312                 /// <summary>
313                 ///     Get a binary value.
314                 /// </summary>
315                 private int GetBinaryValue (RegistryKey rkey, string name, RegistryValueKind type, out byte[] data, int size)
316                 {
317                         byte[] internalData = new byte [size];
318                         IntPtr handle = GetHandle (rkey);
319                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
320                         data = internalData;
321                         return result;
322                 }
323
324                 
325                 // Arbitrary max size for key/values names that can be fetched.
326                 // .NET framework SDK docs say that the max name length that can 
327                 // be used is 255 characters, we'll allow for a bit more.
328                 const int BufferMaxLength = 1024;
329                 
330                 public int SubKeyCount (RegistryKey rkey)
331                 {
332                         int index;
333                         StringBuilder stringBuffer = new StringBuilder (BufferMaxLength);
334                         IntPtr handle = GetHandle (rkey);
335                         
336                         for (index = 0; true; index ++) {
337                                 int result = RegEnumKey (handle, index, stringBuffer,
338                                         stringBuffer.Capacity);
339
340                                 if (result == Win32ResultCode.MarkedForDeletion)
341                                         throw RegistryKey.CreateMarkedForDeletionException ();
342
343                                 if (result == Win32ResultCode.Success)
344                                         continue;
345                                 
346                                 if (result == Win32ResultCode.NoMoreEntries)
347                                         break;
348                                 
349                                 // something is wrong!!
350                                 GenerateException (result);
351                         }
352                         return index;
353                 }
354
355                 public int ValueCount (RegistryKey rkey)
356                 {
357                         int index, result, bufferCapacity;
358                         RegistryValueKind type;
359                         StringBuilder buffer = new StringBuilder (BufferMaxLength);
360                         
361                         IntPtr handle = GetHandle (rkey);
362                         for (index = 0; true; index ++) {
363                                 type = 0;
364                                 bufferCapacity = buffer.Capacity;
365                                 result = RegEnumValue (handle, index, 
366                                                        buffer, ref bufferCapacity,
367                                                        IntPtr.Zero, ref type, 
368                                                        IntPtr.Zero, IntPtr.Zero);
369
370                                 if (result == Win32ResultCode.MarkedForDeletion)
371                                         throw RegistryKey.CreateMarkedForDeletionException ();
372
373                                 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
374                                         continue;
375                                 
376                                 if (result == Win32ResultCode.NoMoreEntries)
377                                         break;
378                                 
379                                 // something is wrong
380                                 GenerateException (result);
381                         }
382                         return index;
383                 }
384
385                 public RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName)
386                 {
387                         IntPtr handle = new IntPtr ((int) hKey);
388
389                         IntPtr keyHandle;
390                         int result = RegConnectRegistry (machineName, handle, out keyHandle);
391                         if (result != Win32ResultCode.Success)
392                                 GenerateException (result);
393
394                         return new RegistryKey (hKey, keyHandle, true);
395                 }
396
397                 public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
398                 {
399                         int access = OpenRegKeyRead;
400                         if (writable) access |= OpenRegKeyWrite;
401                         IntPtr handle = GetHandle (rkey);
402                         
403                         IntPtr subKeyHandle;
404                         int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
405
406                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
407                                 return null;
408                         
409                         if (result != Win32ResultCode.Success)
410                                 GenerateException (result);
411                         
412                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
413                 }
414
415                 public void Flush (RegistryKey rkey)
416                 {
417                         if (!IsHandleValid (rkey))
418                                 return;
419                         IntPtr handle = GetHandle (rkey);
420                         RegFlushKey (handle);
421                 }
422
423                 public void Close (RegistryKey rkey)
424                 {
425                         if (!IsHandleValid (rkey))
426                                 return;
427                         IntPtr handle = GetHandle (rkey);
428                         RegCloseKey (handle);
429                 }
430
431 #if NET_4_0
432                 public RegistryKey FromHandle (SafeRegistryHandle handle)
433                 {
434                         // At this point we can't tell whether the key is writable
435                         // or not (nor the name), so we let the error check code handle it later, as
436                         // .Net seems to do.
437                         return new RegistryKey (handle.DangerousGetHandle (), String.Empty, true);
438                 }
439 #endif
440
441                 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
442                 {
443                         IntPtr handle = GetHandle (rkey);
444                         IntPtr subKeyHandle;
445                         int disposition;
446                         int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
447                                 RegOptionsNonVolatile,
448                                 OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
449
450                         if (result == Win32ResultCode.MarkedForDeletion)
451                                 throw RegistryKey.CreateMarkedForDeletionException ();
452
453                         if (result != Win32ResultCode.Success) {
454                                 GenerateException (result);
455                         }
456                         
457                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
458                                 true);
459                 }
460
461 #if NET_4_0
462                 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName, RegistryOptions options)
463                 {
464                         IntPtr handle = GetHandle (rkey);
465                         IntPtr subKeyHandle;
466                         int disposition;
467                         int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
468                                 options == RegistryOptions.Volatile ? RegOptionsVolatile : RegOptionsNonVolatile,
469                                 OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
470
471                         if (result == Win32ResultCode.MarkedForDeletion)
472                                 throw RegistryKey.CreateMarkedForDeletionException ();
473
474                         if (result != Win32ResultCode.Success)
475                                 GenerateException (result);
476                         
477                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
478                                 true);
479                 }
480 #endif
481
482                 public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
483                 {
484                         IntPtr handle = GetHandle (rkey);
485                         int result = RegDeleteKey (handle, keyName);
486
487                         if (result == Win32ResultCode.FileNotFound) {
488                                 if (shouldThrowWhenKeyMissing)
489                                         throw new ArgumentException ("key " + keyName);
490                                 return;
491                         }
492                         
493                         if (result != Win32ResultCode.Success)
494                                 GenerateException (result);
495                 }
496
497                 public void DeleteValue (RegistryKey rkey, string value, bool shouldThrowWhenKeyMissing)
498                 {
499                         IntPtr handle = GetHandle (rkey);
500                         int result = RegDeleteValue (handle, value);
501
502                         if (result == Win32ResultCode.MarkedForDeletion)
503                                 return;
504
505                         if (result == Win32ResultCode.FileNotFound){
506                                 if (shouldThrowWhenKeyMissing)
507                                         throw new ArgumentException ("value " + value);
508                                 return;
509                         }
510                         
511                         if (result != Win32ResultCode.Success)
512                                 GenerateException (result);
513                 }
514
515                 public string [] GetSubKeyNames (RegistryKey rkey)
516                 {
517                         IntPtr handle = GetHandle (rkey);
518                         StringBuilder buffer = new StringBuilder (BufferMaxLength);
519                         ArrayList keys = new ArrayList ();
520                                 
521                         for (int index = 0; true; index ++) {
522                                 int result = RegEnumKey (handle, index, buffer, buffer.Capacity);
523
524                                 if (result == Win32ResultCode.Success) {
525                                         keys.Add (buffer.ToString ());
526                                         buffer.Length = 0;
527                                         continue;
528                                 }
529
530                                 if (result == Win32ResultCode.NoMoreEntries)
531                                         break;
532
533                                 // should not be here!
534                                 GenerateException (result);
535                         }
536                         return (string []) keys.ToArray (typeof(String));
537                 }
538
539
540                 public string [] GetValueNames (RegistryKey rkey)
541                 {
542                         IntPtr handle = GetHandle (rkey);
543                         ArrayList values = new ArrayList ();
544                         
545                         for (int index = 0; true; index ++)
546                         {
547                                 StringBuilder buffer = new StringBuilder (BufferMaxLength);
548                                 int bufferCapacity = buffer.Capacity;
549                                 RegistryValueKind type = 0;
550                                 
551                                 int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
552                                                         IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
553
554                                 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData) {
555                                         values.Add (buffer.ToString ());
556                                         continue;
557                                 }
558                                 
559                                 if (result == Win32ResultCode.NoMoreEntries)
560                                         break;
561
562                                 if (result == Win32ResultCode.MarkedForDeletion)
563                                         throw RegistryKey.CreateMarkedForDeletionException ();
564
565                                 GenerateException (result);
566                         }
567
568                         return (string []) values.ToArray (typeof(String));
569                 }
570
571                 /// <summary>
572                 /// convert a win32 error code into an appropriate exception.
573                 /// </summary>
574                 private void GenerateException (int errorCode)
575                 {
576                         switch (errorCode) {
577                                 case Win32ResultCode.FileNotFound:
578                                 case Win32ResultCode.InvalidParameter:
579                                         throw new ArgumentException ();
580                                 case Win32ResultCode.AccessDenied:
581                                         throw new SecurityException ();
582                                 case Win32ResultCode.NetworkPathNotFound:
583                                         throw new IOException ("The network path was not found.");
584                                 case Win32ResultCode.InvalidHandle:
585                                         throw new IOException ("Invalid handle.");
586                                 default:
587                                         // unidentified system exception
588                                         throw new SystemException ();
589                         }
590                 }
591
592                 public string ToString (RegistryKey rkey)
593                 {
594                         return rkey.Name;
595                 }
596
597                 /// <summary>
598                 ///     utility: Combine the sub key name to the current name to produce a 
599                 ///     fully qualified sub key name.
600                 /// </summary>
601                 internal static string CombineName (RegistryKey rkey, string localName)
602                 {
603                         return String.Concat (rkey.Name, "\\", localName);
604                 }
605         }
606 }
607
608 #endif // NET_2_1
609