Modify Jenkins scripts to enable babysitter script on Cygwin
[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 !MOBILE
37
38 using System;
39 using System.Collections;
40 using System.Collections.Generic;
41 using System.IO;
42 using System.Runtime.InteropServices;
43 using System.Security;
44 using System.Text;
45 using Microsoft.Win32.SafeHandles;
46
47 namespace Microsoft.Win32
48 {
49         /// <summary>
50         ///     Function stubs, constants and helper functions for
51         ///     the Win32 registry manipulation utilities.
52         /// </summary>
53         internal class Win32RegistryApi : IRegistryApi
54         {
55                 // bit masks for registry key open access permissions
56                 const int OpenRegKeyRead = 0x00020019; 
57                 const int OpenRegKeyWrite = 0x00020006; 
58
59                 // FIXME must be a way to determin this dynamically?
60                 const int Int32ByteSize = 4;
61                 const int Int64ByteSize = 8;
62
63                 // FIXME this is hard coded on Mono, can it be determined dynamically? 
64                 readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
65
66                 const int RegOptionsNonVolatile = 0x00000000;
67                 const int RegOptionsVolatile = 0x00000001;
68
69                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKeyEx")]
70                 static extern int RegCreateKeyEx (IntPtr keyBase, string keyName, int reserved, 
71                         IntPtr lpClass, int options, int access, IntPtr securityAttrs,
72                         out IntPtr keyHandle, out int disposition);
73                
74                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
75                 static extern int RegCloseKey (IntPtr keyHandle);
76
77                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
78                 static extern int RegConnectRegistry (string machineName, IntPtr hKey,
79                                 out IntPtr keyHandle);
80
81                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
82                 private static extern int RegFlushKey (IntPtr keyHandle);
83
84                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
85                 private static extern int RegOpenKeyEx (IntPtr keyBase,
86                                 string keyName, IntPtr reserved, int access,
87                                 out IntPtr keyHandle);
88
89                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
90                 private static extern int RegDeleteKey (IntPtr keyHandle, string valueName);
91
92                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
93                 private static extern int RegDeleteValue (IntPtr keyHandle, string valueName);
94
95                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
96                 private static extern int RegEnumKey (IntPtr keyBase, int index, StringBuilder nameBuffer, int bufferLength);
97
98                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
99                 private static extern int RegEnumValue (IntPtr keyBase, 
100                                 int index, StringBuilder nameBuffer, 
101                                 ref int nameLength, IntPtr reserved, 
102                                 ref RegistryValueKind type, IntPtr data, IntPtr dataLength);
103
104 //              [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
105 //              private static extern int RegSetValueEx (IntPtr keyBase, 
106 //                              string valueName, IntPtr reserved, RegistryValueKind type,
107 //                              StringBuilder data, int rawDataLength);
108
109                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
110                 private static extern int RegSetValueEx (IntPtr keyBase, 
111                                 string valueName, IntPtr reserved, RegistryValueKind type,
112                                 string data, int rawDataLength);
113
114                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
115                 private static extern int RegSetValueEx (IntPtr keyBase, 
116                                 string valueName, IntPtr reserved, RegistryValueKind type,
117                                 byte[] rawData, int rawDataLength);
118
119                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
120                 private static extern int RegSetValueEx (IntPtr keyBase, 
121                                 string valueName, IntPtr reserved, RegistryValueKind type,
122                                 ref int data, int rawDataLength);
123
124                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
125                 private static extern int RegSetValueEx (IntPtr keyBase, 
126                                 string valueName, IntPtr reserved, RegistryValueKind type,
127                                 ref long data, int rawDataLength);
128
129                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
130                 private static extern int RegQueryValueEx (IntPtr keyBase,
131                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
132                                 IntPtr zero, ref int dataSize);
133
134                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
135                 private static extern int RegQueryValueEx (IntPtr keyBase,
136                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
137                                 [Out] byte[] data, ref int dataSize);
138
139                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
140                 private static extern int RegQueryValueEx (IntPtr keyBase,
141                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
142                                 ref int data, ref int dataSize);
143
144                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
145                 private static extern int RegQueryValueEx (IntPtr keyBase,
146                                 string valueName, IntPtr reserved, ref RegistryValueKind type,
147                                 ref long data, ref int dataSize);
148
149                 // Returns our handle from the RegistryKey
150                 public IntPtr GetHandle (RegistryKey key)
151                 {
152                         return (IntPtr) key.InternalHandle;
153                 }
154
155                 static bool IsHandleValid (RegistryKey key)
156                 {
157                         return key.InternalHandle != null;
158                 }
159
160                 public RegistryValueKind GetValueKind (RegistryKey rkey, string name)
161                 {
162                         RegistryValueKind type = 0;
163                         int size = 0;
164                         IntPtr handle = GetHandle (rkey);
165                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
166
167                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) 
168                                 return RegistryValueKind.Unknown;
169
170                         return type;
171                 }
172                 
173                 /// <summary>
174                 /// Acctually read a registry value. Requires knowledge of the
175                 /// value's type and size.
176                 /// </summary>
177                 public object GetValue (RegistryKey rkey, string name, object defaultValue, RegistryValueOptions options)
178                 {
179                         RegistryValueKind type = 0;
180                         int size = 0;
181                         object obj = null;
182                         IntPtr handle = GetHandle (rkey);
183                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
184
185                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) {
186                                 return defaultValue;
187                         }
188                         
189                         if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success ) {
190                                 GenerateException (result);
191                         }
192                         
193                         if (type == RegistryValueKind.String) {
194                                 byte[] data;
195                                 result = GetBinaryValue (rkey, name, type, out data, size);
196                                 obj = RegistryKey.DecodeString (data);
197                         } else if (type == RegistryValueKind.ExpandString) {
198                                 byte [] data;
199                                 result = GetBinaryValue (rkey, name, type, out data, size);
200                                 obj = RegistryKey.DecodeString (data);
201                                 if ((options & RegistryValueOptions.DoNotExpandEnvironmentNames) == 0)
202                                         obj = Environment.ExpandEnvironmentVariables ((string) obj);
203                         } else if (type == RegistryValueKind.DWord) {
204                                 int data = 0;
205                                 result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
206                                 obj = data;
207                         } else if (type == RegistryValueKind.QWord) {
208                                 long data = 0;
209                                 result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
210                                 obj = data;
211                         } else if (type == RegistryValueKind.Binary) {
212                                 byte[] data;
213                                 result = GetBinaryValue (rkey, name, type, out data, size);
214                                 obj = data;
215                         } else if (type == RegistryValueKind.MultiString) {
216                                 obj = null;
217                                 byte[] data;
218                                 result = GetBinaryValue (rkey, name, type, out data, size);
219                                 
220                                 if (result == Win32ResultCode.Success)
221                                         obj = RegistryKey.DecodeString (data).Split ('\0');
222                         } else {
223                                 // should never get here
224                                 throw new SystemException ();
225                         }
226
227                         // check result codes again:
228                         if (result != Win32ResultCode.Success)
229                         {
230                                 GenerateException (result);
231                         }
232                         
233
234                         return obj;
235                 }
236
237                 //
238                 // This version has to do extra checking, make sure that the requested
239                 // valueKind matches the type of the value being stored
240                 //
241                 public void SetValue (RegistryKey rkey, string name, object value, RegistryValueKind valueKind)
242                 {
243                         Type type = value.GetType ();
244                         IntPtr handle = GetHandle (rkey);
245
246                         switch (valueKind) {
247                         case RegistryValueKind.QWord:
248                                 try {
249                                         long rawValue = Convert.ToInt64 (value);
250                                         CheckResult (RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.QWord, ref rawValue, Int64ByteSize));
251                                         return;
252                                 } catch (OverflowException) {
253                                 }
254                                 break;
255                         case RegistryValueKind.DWord:
256                                 try {
257                                         int rawValue = Convert.ToInt32 (value);
258                                         CheckResult (RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize));
259                                         return;
260                                 } catch (OverflowException) {
261                                 }
262                                 break;
263                         case RegistryValueKind.Binary:
264                                 if (type == typeof (byte[])) {
265                                         byte[] rawValue = (byte[]) value;
266                                         CheckResult (RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length));
267                                         return;
268                                 }
269                                 break;
270                         case RegistryValueKind.MultiString:
271                                 if (type == typeof (string[])) {
272                                         string[] vals = (string[]) value;
273                                         StringBuilder fullStringValue = new StringBuilder ();
274                                         foreach (string v in vals)
275                                         {
276                                                 fullStringValue.Append (v);
277                                                 fullStringValue.Append ('\0');
278                                         }
279                                         fullStringValue.Append ('\0');
280
281                                         byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
282                         
283                                         CheckResult (RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length));
284                                         return;
285                                 }
286                                 break;
287                         case RegistryValueKind.String:
288                         case RegistryValueKind.ExpandString:
289                                 if (type == typeof (string)) {
290                                         string rawValue = String.Format ("{0}{1}", value, '\0');
291                                         CheckResult (RegSetValueEx (handle, name, IntPtr.Zero, valueKind, rawValue,
292                                                                 rawValue.Length * NativeBytesPerCharacter));
293                                         return;
294                                 }
295                                 break;
296                         default:
297                                 if (type.IsArray) {
298                                         throw new ArgumentException ("Only string and byte arrays can written as registry values");
299                                 }
300                                 break;
301                         }
302
303                         throw new ArgumentException ("Type does not match the valueKind");
304                 }
305         
306                 public void SetValue (RegistryKey rkey, string name, object value)
307                 {
308                         Type type = value.GetType ();
309                         int result;
310                         IntPtr handle = GetHandle (rkey);
311
312                         if (type == typeof (int)) {
313                                 int rawValue = (int)value;
314                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize); 
315                         } else if (type == typeof (byte[])) {
316                                 byte[] rawValue = (byte[]) value;
317                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
318                         } else if (type == typeof (string[])) {
319                                 string[] vals = (string[]) value;
320                                 StringBuilder fullStringValue = new StringBuilder ();
321                                 foreach (string v in vals)
322                                 {
323                                         fullStringValue.Append (v);
324                                         fullStringValue.Append ('\0');
325                                 }
326                                 fullStringValue.Append ('\0');
327
328                                 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
329                         
330                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length); 
331                         } else if (type.IsArray) {
332                                 throw new ArgumentException ("Only string and byte arrays can written as registry values");
333                         } else {
334                                 string rawValue = String.Format ("{0}{1}", value, '\0');
335                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.String, rawValue,
336                                                         rawValue.Length * NativeBytesPerCharacter);
337                         }
338
339                         // handle the result codes
340                         if (result != Win32ResultCode.Success)
341                         {
342                                 GenerateException (result);
343                         }
344                 }
345
346                 /// <summary>
347                 ///     Get a binary value.
348                 /// </summary>
349                 private int GetBinaryValue (RegistryKey rkey, string name, RegistryValueKind type, out byte[] data, int size)
350                 {
351                         byte[] internalData = new byte [size];
352                         IntPtr handle = GetHandle (rkey);
353                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
354                         data = internalData;
355                         return result;
356                 }
357
358                 
359                 // Arbitrary max size for key/values names that can be fetched.
360                 // .NET framework SDK docs say that the max name length that can 
361                 // be used is 255 characters, we'll allow for a bit more.
362                 const int BufferMaxLength = 1024;
363                 
364                 public int SubKeyCount (RegistryKey rkey)
365                 {
366                         int index;
367                         StringBuilder stringBuffer = new StringBuilder (BufferMaxLength);
368                         IntPtr handle = GetHandle (rkey);
369                         
370                         for (index = 0; true; index ++) {
371                                 int result = RegEnumKey (handle, index, stringBuffer,
372                                         stringBuffer.Capacity);
373
374                                 if (result == Win32ResultCode.Success)
375                                         continue;
376                                 
377                                 if (result == Win32ResultCode.NoMoreEntries)
378                                         break;
379                                 
380                                 // something is wrong!!
381                                 GenerateException (result);
382                         }
383                         return index;
384                 }
385
386                 public int ValueCount (RegistryKey rkey)
387                 {
388                         int index, result, bufferCapacity;
389                         RegistryValueKind type;
390                         StringBuilder buffer = new StringBuilder (BufferMaxLength);
391                         
392                         IntPtr handle = GetHandle (rkey);
393                         for (index = 0; true; index ++) {
394                                 type = 0;
395                                 bufferCapacity = buffer.Capacity;
396                                 result = RegEnumValue (handle, index, 
397                                                        buffer, ref bufferCapacity,
398                                                        IntPtr.Zero, ref type, 
399                                                        IntPtr.Zero, IntPtr.Zero);
400
401                                 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
402                                         continue;
403                                 
404                                 if (result == Win32ResultCode.NoMoreEntries)
405                                         break;
406                                 
407                                 // something is wrong
408                                 GenerateException (result);
409                         }
410                         return index;
411                 }
412
413                 public RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName)
414                 {
415                         IntPtr handle = new IntPtr ((int) hKey);
416
417                         IntPtr keyHandle;
418                         int result = RegConnectRegistry (machineName, handle, out keyHandle);
419                         if (result != Win32ResultCode.Success)
420                                 GenerateException (result);
421
422                         return new RegistryKey (hKey, keyHandle, true);
423                 }
424
425                 public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
426                 {
427                         int access = OpenRegKeyRead;
428                         if (writable) access |= OpenRegKeyWrite;
429                         IntPtr handle = GetHandle (rkey);
430                         
431                         IntPtr subKeyHandle;
432                         int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
433
434                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
435                                 return null;
436                         
437                         if (result != Win32ResultCode.Success)
438                                 GenerateException (result);
439                         
440                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
441                 }
442
443                 public void Flush (RegistryKey rkey)
444                 {
445                         if (!IsHandleValid (rkey))
446                                 return;
447                         IntPtr handle = GetHandle (rkey);
448                         RegFlushKey (handle);
449                 }
450
451                 public void Close (RegistryKey rkey)
452                 {
453                         if (!IsHandleValid (rkey))
454                                 return;
455                         SafeRegistryHandle safe_handle = rkey.Handle;
456                         if (safe_handle != null) {
457                                 // closes the unmanaged pointer for us.
458                                 safe_handle.Close ();
459                                 return;
460                         }
461                         IntPtr handle = GetHandle (rkey);
462                         RegCloseKey (handle);
463                 }
464
465                 public RegistryKey FromHandle (SafeRegistryHandle handle)
466                 {
467                         // At this point we can't tell whether the key is writable
468                         // or not (nor the name), so we let the error check code handle it later, as
469                         // .Net seems to do.
470                         return new RegistryKey (handle.DangerousGetHandle (), String.Empty, true);
471                 }
472
473                 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
474                 {
475                         IntPtr handle = GetHandle (rkey);
476                         IntPtr subKeyHandle;
477                         int disposition;
478                         int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
479                                 RegOptionsNonVolatile,
480                                 OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
481
482                         if (result != Win32ResultCode.Success) {
483                                 GenerateException (result);
484                         }
485                         
486                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
487                                 true);
488                 }
489
490                 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName, RegistryOptions options)
491                 {
492                         IntPtr handle = GetHandle (rkey);
493                         IntPtr subKeyHandle;
494                         int disposition;
495                         int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
496                                 options == RegistryOptions.Volatile ? RegOptionsVolatile : RegOptionsNonVolatile,
497                                 OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
498
499                         if (result != Win32ResultCode.Success)
500                                 GenerateException (result);
501                         
502                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
503                                 true);
504                 }
505
506                 public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
507                 {
508                         IntPtr handle = GetHandle (rkey);
509                         int result = RegDeleteKey (handle, keyName);
510
511                         if (result == Win32ResultCode.FileNotFound) {
512                                 if (shouldThrowWhenKeyMissing)
513                                         throw new ArgumentException ("key " + keyName);
514                                 return;
515                         }
516                         
517                         if (result != Win32ResultCode.Success)
518                                 GenerateException (result);
519                 }
520
521                 public void DeleteValue (RegistryKey rkey, string value, bool shouldThrowWhenKeyMissing)
522                 {
523                         IntPtr handle = GetHandle (rkey);
524                         int result = RegDeleteValue (handle, value);
525
526                         if (result == Win32ResultCode.MarkedForDeletion)
527                                 return;
528
529                         if (result == Win32ResultCode.FileNotFound){
530                                 if (shouldThrowWhenKeyMissing)
531                                         throw new ArgumentException ("value " + value);
532                                 return;
533                         }
534                         
535                         if (result != Win32ResultCode.Success)
536                                 GenerateException (result);
537                 }
538
539                 public string [] GetSubKeyNames (RegistryKey rkey)
540                 {
541                         IntPtr handle = GetHandle (rkey);
542                         StringBuilder buffer = new StringBuilder (BufferMaxLength);
543                         var keys = new List<string> ();
544                                 
545                         for (int index = 0; true; index ++) {
546                                 int result = RegEnumKey (handle, index, buffer, buffer.Capacity);
547
548                                 if (result == Win32ResultCode.Success) {
549                                         keys.Add (buffer.ToString ());
550                                         buffer.Length = 0;
551                                         continue;
552                                 }
553
554                                 if (result == Win32ResultCode.NoMoreEntries)
555                                         break;
556
557                                 // should not be here!
558                                 GenerateException (result);
559                         }
560                         return keys.ToArray ();
561                 }
562
563
564                 public string [] GetValueNames (RegistryKey rkey)
565                 {
566                         IntPtr handle = GetHandle (rkey);
567                         var values = new List<string> ();
568                         
569                         for (int index = 0; true; index ++)
570                         {
571                                 StringBuilder buffer = new StringBuilder (BufferMaxLength);
572                                 int bufferCapacity = buffer.Capacity;
573                                 RegistryValueKind type = 0;
574                                 
575                                 int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
576                                                         IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
577
578                                 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData) {
579                                         values.Add (buffer.ToString ());
580                                         continue;
581                                 }
582                                 
583                                 if (result == Win32ResultCode.NoMoreEntries)
584                                         break;
585
586                                 GenerateException (result);
587                         }
588
589                         return values.ToArray ();
590                 }
591
592                 private void CheckResult (int result)
593                 {
594                         if (result != Win32ResultCode.Success) {
595                                 GenerateException (result);
596                         }
597                 }
598
599                 /// <summary>
600                 /// convert a win32 error code into an appropriate exception.
601                 /// </summary>
602                 private void GenerateException (int errorCode)
603                 {
604                         switch (errorCode) {
605                                 case Win32ResultCode.FileNotFound:
606                                 case Win32ResultCode.InvalidParameter:
607                                         throw new ArgumentException ();
608                                 case Win32ResultCode.AccessDenied:
609                                         throw new SecurityException ();
610                                 case Win32ResultCode.NetworkPathNotFound:
611                                         throw new IOException ("The network path was not found.");
612                                 case Win32ResultCode.InvalidHandle:
613                                         throw new IOException ("Invalid handle.");
614                                 case Win32ResultCode.MarkedForDeletion:
615                                         throw RegistryKey.CreateMarkedForDeletionException ();
616                                 case Win32ResultCode.ChildMustBeVolatile:
617                                         throw new IOException ("Cannot create a stable subkey under a volatile parent key.");
618                                 default:
619                                         // unidentified system exception
620                                         throw new SystemException ();
621                         }
622                 }
623
624                 public string ToString (RegistryKey rkey)
625                 {
626                         return rkey.Name;
627                 }
628
629                 /// <summary>
630                 ///     utility: Combine the sub key name to the current name to produce a 
631                 ///     fully qualified sub key name.
632                 /// </summary>
633                 internal static string CombineName (RegistryKey rkey, string localName)
634                 {
635                         return String.Concat (rkey.Name, "\\", localName);
636                 }
637         }
638 }
639
640 #endif // MOBILE
641