Merge pull request #853 from echampet/onclick
[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.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                         int result;
245                         IntPtr handle = GetHandle (rkey);
246
247                         if (valueKind == RegistryValueKind.QWord && type == typeof (long)) {
248                                 long rawValue = (long)value;
249                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.QWord, ref rawValue, Int64ByteSize); 
250                         } else if (valueKind == RegistryValueKind.DWord && type == typeof (int)) {
251                                 int rawValue = (int)value;
252                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize); 
253                         } else if (valueKind == RegistryValueKind.Binary && type == typeof (byte[])) {
254                                 byte[] rawValue = (byte[]) value;
255                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
256                         } else if (valueKind == RegistryValueKind.MultiString && type == typeof (string[])) {
257                                 string[] vals = (string[]) value;
258                                 StringBuilder fullStringValue = new StringBuilder ();
259                                 foreach (string v in vals)
260                                 {
261                                         fullStringValue.Append (v);
262                                         fullStringValue.Append ('\0');
263                                 }
264                                 fullStringValue.Append ('\0');
265
266                                 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
267                         
268                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length); 
269                         } else if ((valueKind == RegistryValueKind.String || valueKind == RegistryValueKind.ExpandString) &&
270                                    type == typeof (string)){
271                                 string rawValue = String.Format ("{0}{1}", value, '\0');
272                                 result = RegSetValueEx (handle, name, IntPtr.Zero, valueKind, rawValue,
273                                                         rawValue.Length * NativeBytesPerCharacter);
274                                 
275                         } else if (type.IsArray) {
276                                 throw new ArgumentException ("Only string and byte arrays can written as registry values");
277                         } else {
278                                 throw new ArgumentException ("Type does not match the valueKind");
279                         }
280
281                         // handle the result codes
282                         if (result != Win32ResultCode.Success)
283                         {
284                                 GenerateException (result);
285                         }
286                 }
287         
288                 public void SetValue (RegistryKey rkey, string name, object value)
289                 {
290                         Type type = value.GetType ();
291                         int result;
292                         IntPtr handle = GetHandle (rkey);
293
294                         if (type == typeof (int)) {
295                                 int rawValue = (int)value;
296                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize); 
297                         } else if (type == typeof (byte[])) {
298                                 byte[] rawValue = (byte[]) value;
299                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
300                         } else if (type == typeof (string[])) {
301                                 string[] vals = (string[]) value;
302                                 StringBuilder fullStringValue = new StringBuilder ();
303                                 foreach (string v in vals)
304                                 {
305                                         fullStringValue.Append (v);
306                                         fullStringValue.Append ('\0');
307                                 }
308                                 fullStringValue.Append ('\0');
309
310                                 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
311                         
312                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length); 
313                         } else if (type.IsArray) {
314                                 throw new ArgumentException ("Only string and byte arrays can written as registry values");
315                         } else {
316                                 string rawValue = String.Format ("{0}{1}", value, '\0');
317                                 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.String, rawValue,
318                                                         rawValue.Length * NativeBytesPerCharacter);
319                         }
320
321                         if (result == Win32ResultCode.MarkedForDeletion)
322                                 throw RegistryKey.CreateMarkedForDeletionException ();
323
324                         // handle the result codes
325                         if (result != Win32ResultCode.Success)
326                         {
327                                 GenerateException (result);
328                         }
329                 }
330
331                 /// <summary>
332                 ///     Get a binary value.
333                 /// </summary>
334                 private int GetBinaryValue (RegistryKey rkey, string name, RegistryValueKind type, out byte[] data, int size)
335                 {
336                         byte[] internalData = new byte [size];
337                         IntPtr handle = GetHandle (rkey);
338                         int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
339                         data = internalData;
340                         return result;
341                 }
342
343                 
344                 // Arbitrary max size for key/values names that can be fetched.
345                 // .NET framework SDK docs say that the max name length that can 
346                 // be used is 255 characters, we'll allow for a bit more.
347                 const int BufferMaxLength = 1024;
348                 
349                 public int SubKeyCount (RegistryKey rkey)
350                 {
351                         int index;
352                         StringBuilder stringBuffer = new StringBuilder (BufferMaxLength);
353                         IntPtr handle = GetHandle (rkey);
354                         
355                         for (index = 0; true; index ++) {
356                                 int result = RegEnumKey (handle, index, stringBuffer,
357                                         stringBuffer.Capacity);
358
359                                 if (result == Win32ResultCode.MarkedForDeletion)
360                                         throw RegistryKey.CreateMarkedForDeletionException ();
361
362                                 if (result == Win32ResultCode.Success)
363                                         continue;
364                                 
365                                 if (result == Win32ResultCode.NoMoreEntries)
366                                         break;
367                                 
368                                 // something is wrong!!
369                                 GenerateException (result);
370                         }
371                         return index;
372                 }
373
374                 public int ValueCount (RegistryKey rkey)
375                 {
376                         int index, result, bufferCapacity;
377                         RegistryValueKind type;
378                         StringBuilder buffer = new StringBuilder (BufferMaxLength);
379                         
380                         IntPtr handle = GetHandle (rkey);
381                         for (index = 0; true; index ++) {
382                                 type = 0;
383                                 bufferCapacity = buffer.Capacity;
384                                 result = RegEnumValue (handle, index, 
385                                                        buffer, ref bufferCapacity,
386                                                        IntPtr.Zero, ref type, 
387                                                        IntPtr.Zero, IntPtr.Zero);
388
389                                 if (result == Win32ResultCode.MarkedForDeletion)
390                                         throw RegistryKey.CreateMarkedForDeletionException ();
391
392                                 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
393                                         continue;
394                                 
395                                 if (result == Win32ResultCode.NoMoreEntries)
396                                         break;
397                                 
398                                 // something is wrong
399                                 GenerateException (result);
400                         }
401                         return index;
402                 }
403
404                 public RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName)
405                 {
406                         IntPtr handle = new IntPtr ((int) hKey);
407
408                         IntPtr keyHandle;
409                         int result = RegConnectRegistry (machineName, handle, out keyHandle);
410                         if (result != Win32ResultCode.Success)
411                                 GenerateException (result);
412
413                         return new RegistryKey (hKey, keyHandle, true);
414                 }
415
416                 public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
417                 {
418                         int access = OpenRegKeyRead;
419                         if (writable) access |= OpenRegKeyWrite;
420                         IntPtr handle = GetHandle (rkey);
421                         
422                         IntPtr subKeyHandle;
423                         int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
424
425                         if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
426                                 return null;
427                         
428                         if (result != Win32ResultCode.Success)
429                                 GenerateException (result);
430                         
431                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
432                 }
433
434                 public void Flush (RegistryKey rkey)
435                 {
436                         if (!IsHandleValid (rkey))
437                                 return;
438                         IntPtr handle = GetHandle (rkey);
439                         RegFlushKey (handle);
440                 }
441
442                 public void Close (RegistryKey rkey)
443                 {
444                         if (!IsHandleValid (rkey))
445                                 return;
446                         SafeRegistryHandle safe_handle = rkey.Handle;
447                         if (safe_handle != null) {
448                                 // closes the unmanaged pointer for us.
449                                 safe_handle.Close ();
450                                 return;
451                         }
452                         IntPtr handle = GetHandle (rkey);
453                         RegCloseKey (handle);
454                 }
455
456                 public RegistryKey FromHandle (SafeRegistryHandle handle)
457                 {
458                         // At this point we can't tell whether the key is writable
459                         // or not (nor the name), so we let the error check code handle it later, as
460                         // .Net seems to do.
461                         return new RegistryKey (handle.DangerousGetHandle (), String.Empty, true);
462                 }
463
464                 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
465                 {
466                         IntPtr handle = GetHandle (rkey);
467                         IntPtr subKeyHandle;
468                         int disposition;
469                         int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
470                                 RegOptionsNonVolatile,
471                                 OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
472
473                         if (result == Win32ResultCode.MarkedForDeletion)
474                                 throw RegistryKey.CreateMarkedForDeletionException ();
475
476                         if (result != Win32ResultCode.Success) {
477                                 GenerateException (result);
478                         }
479                         
480                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
481                                 true);
482                 }
483
484                 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName, RegistryOptions options)
485                 {
486                         IntPtr handle = GetHandle (rkey);
487                         IntPtr subKeyHandle;
488                         int disposition;
489                         int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
490                                 options == RegistryOptions.Volatile ? RegOptionsVolatile : RegOptionsNonVolatile,
491                                 OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
492
493                         if (result == Win32ResultCode.MarkedForDeletion)
494                                 throw RegistryKey.CreateMarkedForDeletionException ();
495
496                         if (result != Win32ResultCode.Success)
497                                 GenerateException (result);
498                         
499                         return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
500                                 true);
501                 }
502
503                 public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
504                 {
505                         IntPtr handle = GetHandle (rkey);
506                         int result = RegDeleteKey (handle, keyName);
507
508                         if (result == Win32ResultCode.FileNotFound) {
509                                 if (shouldThrowWhenKeyMissing)
510                                         throw new ArgumentException ("key " + keyName);
511                                 return;
512                         }
513                         
514                         if (result != Win32ResultCode.Success)
515                                 GenerateException (result);
516                 }
517
518                 public void DeleteValue (RegistryKey rkey, string value, bool shouldThrowWhenKeyMissing)
519                 {
520                         IntPtr handle = GetHandle (rkey);
521                         int result = RegDeleteValue (handle, value);
522
523                         if (result == Win32ResultCode.MarkedForDeletion)
524                                 return;
525
526                         if (result == Win32ResultCode.FileNotFound){
527                                 if (shouldThrowWhenKeyMissing)
528                                         throw new ArgumentException ("value " + value);
529                                 return;
530                         }
531                         
532                         if (result != Win32ResultCode.Success)
533                                 GenerateException (result);
534                 }
535
536                 public string [] GetSubKeyNames (RegistryKey rkey)
537                 {
538                         IntPtr handle = GetHandle (rkey);
539                         StringBuilder buffer = new StringBuilder (BufferMaxLength);
540                         var keys = new List<string> ();
541                                 
542                         for (int index = 0; true; index ++) {
543                                 int result = RegEnumKey (handle, index, buffer, buffer.Capacity);
544
545                                 if (result == Win32ResultCode.Success) {
546                                         keys.Add (buffer.ToString ());
547                                         buffer.Length = 0;
548                                         continue;
549                                 }
550
551                                 if (result == Win32ResultCode.NoMoreEntries)
552                                         break;
553
554                                 // should not be here!
555                                 GenerateException (result);
556                         }
557                         return keys.ToArray ();
558                 }
559
560
561                 public string [] GetValueNames (RegistryKey rkey)
562                 {
563                         IntPtr handle = GetHandle (rkey);
564                         var values = new List<string> ();
565                         
566                         for (int index = 0; true; index ++)
567                         {
568                                 StringBuilder buffer = new StringBuilder (BufferMaxLength);
569                                 int bufferCapacity = buffer.Capacity;
570                                 RegistryValueKind type = 0;
571                                 
572                                 int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
573                                                         IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
574
575                                 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData) {
576                                         values.Add (buffer.ToString ());
577                                         continue;
578                                 }
579                                 
580                                 if (result == Win32ResultCode.NoMoreEntries)
581                                         break;
582
583                                 if (result == Win32ResultCode.MarkedForDeletion)
584                                         throw RegistryKey.CreateMarkedForDeletionException ();
585
586                                 GenerateException (result);
587                         }
588
589                         return values.ToArray ();
590                 }
591
592                 /// <summary>
593                 /// convert a win32 error code into an appropriate exception.
594                 /// </summary>
595                 private void GenerateException (int errorCode)
596                 {
597                         switch (errorCode) {
598                                 case Win32ResultCode.FileNotFound:
599                                 case Win32ResultCode.InvalidParameter:
600                                         throw new ArgumentException ();
601                                 case Win32ResultCode.AccessDenied:
602                                         throw new SecurityException ();
603                                 case Win32ResultCode.NetworkPathNotFound:
604                                         throw new IOException ("The network path was not found.");
605                                 case Win32ResultCode.InvalidHandle:
606                                         throw new IOException ("Invalid handle.");
607                                 default:
608                                         // unidentified system exception
609                                         throw new SystemException ();
610                         }
611                 }
612
613                 public string ToString (RegistryKey rkey)
614                 {
615                         return rkey.Name;
616                 }
617
618                 /// <summary>
619                 ///     utility: Combine the sub key name to the current name to produce a 
620                 ///     fully qualified sub key name.
621                 /// </summary>
622                 internal static string CombineName (RegistryKey rkey, string localName)
623                 {
624                         return String.Concat (rkey.Name, "\\", localName);
625                 }
626         }
627 }
628
629 #endif // NET_2_1
630