GenericParameter.cs: override Module properly
[mcs.git] / class / corlib / Microsoft.Win32 / Win32RegistryApi.cs
blob9ffa21c3602901c516c0f824678f7817770beeaf
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 //
14 // Copyright (C) 2004, 2005 Novell, Inc (http://www.novell.com)
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.
36 #if !NET_2_1
38 using System;
39 using System.Collections;
40 using System.IO;
41 using System.Runtime.InteropServices;
42 using System.Security;
43 using System.Text;
45 namespace Microsoft.Win32
47 /// <summary>
48 /// Function stubs, constants and helper functions for
49 /// the Win32 registry manipulation utilities.
50 /// </summary>
51 internal class Win32RegistryApi : IRegistryApi
53 // bit masks for registry key open access permissions
54 const int OpenRegKeyRead = 0x00020019;
55 const int OpenRegKeyWrite = 0x00020006;
57 // FIXME must be a way to determin this dynamically?
58 const int Int32ByteSize = 4;
60 // FIXME this is hard coded on Mono, can it be determined dynamically?
61 readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
63 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKey")]
64 static extern int RegCreateKey (IntPtr keyBase, string keyName, out IntPtr keyHandle);
66 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
67 static extern int RegCloseKey (IntPtr keyHandle);
69 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
70 static extern int RegConnectRegistry (string machineName, IntPtr hKey,
71 out IntPtr keyHandle);
73 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
74 private static extern int RegFlushKey (IntPtr keyHandle);
76 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
77 private static extern int RegOpenKeyEx (IntPtr keyBase,
78 string keyName, IntPtr reserved, int access,
79 out IntPtr keyHandle);
81 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
82 private static extern int RegDeleteKey (IntPtr keyHandle, string valueName);
84 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
85 private static extern int RegDeleteValue (IntPtr keyHandle, string valueName);
87 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
88 private static extern int RegEnumKey (IntPtr keyBase, int index, StringBuilder nameBuffer, int bufferLength);
90 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
91 private static extern int RegEnumValue (IntPtr keyBase,
92 int index, StringBuilder nameBuffer,
93 ref int nameLength, IntPtr reserved,
94 ref RegistryValueKind type, IntPtr data, IntPtr dataLength);
96 // [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
97 // private static extern int RegSetValueEx (IntPtr keyBase,
98 // string valueName, IntPtr reserved, RegistryValueKind type,
99 // StringBuilder data, int rawDataLength);
101 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
102 private static extern int RegSetValueEx (IntPtr keyBase,
103 string valueName, IntPtr reserved, RegistryValueKind type,
104 string data, int rawDataLength);
106 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
107 private static extern int RegSetValueEx (IntPtr keyBase,
108 string valueName, IntPtr reserved, RegistryValueKind type,
109 byte[] rawData, int rawDataLength);
111 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
112 private static extern int RegSetValueEx (IntPtr keyBase,
113 string valueName, IntPtr reserved, RegistryValueKind type,
114 ref int data, int rawDataLength);
116 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
117 private static extern int RegQueryValueEx (IntPtr keyBase,
118 string valueName, IntPtr reserved, ref RegistryValueKind type,
119 IntPtr zero, ref int dataSize);
121 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
122 private static extern int RegQueryValueEx (IntPtr keyBase,
123 string valueName, IntPtr reserved, ref RegistryValueKind type,
124 [Out] byte[] data, ref int dataSize);
126 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
127 private static extern int RegQueryValueEx (IntPtr keyBase,
128 string valueName, IntPtr reserved, ref RegistryValueKind type,
129 ref int data, ref int dataSize);
131 // Returns our handle from the RegistryKey
132 static IntPtr GetHandle (RegistryKey key)
134 return (IntPtr) key.Handle;
137 static bool IsHandleValid (RegistryKey key)
139 return key.Handle != null;
142 public RegistryValueKind GetValueKind (RegistryKey rkey, string name)
144 RegistryValueKind type = 0;
145 int size = 0;
146 IntPtr handle = GetHandle (rkey);
147 int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
149 if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
150 return RegistryValueKind.Unknown;
152 return type;
155 /// <summary>
156 /// Acctually read a registry value. Requires knowledge of the
157 /// value's type and size.
158 /// </summary>
159 public object GetValue (RegistryKey rkey, string name, object defaultValue, RegistryValueOptions options)
161 RegistryValueKind type = 0;
162 int size = 0;
163 object obj = null;
164 IntPtr handle = GetHandle (rkey);
165 int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
167 if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) {
168 return defaultValue;
171 if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success ) {
172 GenerateException (result);
175 if (type == RegistryValueKind.String) {
176 byte[] data;
177 result = GetBinaryValue (rkey, name, type, out data, size);
178 obj = RegistryKey.DecodeString (data);
179 } else if (type == RegistryValueKind.ExpandString) {
180 byte [] data;
181 result = GetBinaryValue (rkey, name, type, out data, size);
182 obj = RegistryKey.DecodeString (data);
183 if ((options & RegistryValueOptions.DoNotExpandEnvironmentNames) == 0)
184 obj = Environment.ExpandEnvironmentVariables ((string) obj);
185 } else if (type == RegistryValueKind.DWord) {
186 int data = 0;
187 result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
188 obj = data;
189 } else if (type == RegistryValueKind.Binary) {
190 byte[] data;
191 result = GetBinaryValue (rkey, name, type, out data, size);
192 obj = data;
193 } else if (type == RegistryValueKind.MultiString) {
194 obj = null;
195 byte[] data;
196 result = GetBinaryValue (rkey, name, type, out data, size);
198 if (result == Win32ResultCode.Success)
199 obj = RegistryKey.DecodeString (data).Split ('\0');
200 } else {
201 // should never get here
202 throw new SystemException ();
205 // check result codes again:
206 if (result != Win32ResultCode.Success)
208 GenerateException (result);
212 return obj;
216 // This version has to do extra checking, make sure that the requested
217 // valueKind matches the type of the value being stored
219 public void SetValue (RegistryKey rkey, string name, object value, RegistryValueKind valueKind)
221 Type type = value.GetType ();
222 int result;
223 IntPtr handle = GetHandle (rkey);
225 if (valueKind == RegistryValueKind.DWord && type == typeof (int)) {
226 int rawValue = (int)value;
227 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize);
228 } else if (valueKind == RegistryValueKind.Binary && type == typeof (byte[])) {
229 byte[] rawValue = (byte[]) value;
230 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
231 } else if (valueKind == RegistryValueKind.MultiString && type == typeof (string[])) {
232 string[] vals = (string[]) value;
233 StringBuilder fullStringValue = new StringBuilder ();
234 foreach (string v in vals)
236 fullStringValue.Append (v);
237 fullStringValue.Append ('\0');
239 fullStringValue.Append ('\0');
241 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
243 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length);
244 } else if ((valueKind == RegistryValueKind.String || valueKind == RegistryValueKind.ExpandString) &&
245 type == typeof (string)){
246 string rawValue = String.Format ("{0}{1}", value, '\0');
247 result = RegSetValueEx (handle, name, IntPtr.Zero, valueKind, rawValue,
248 rawValue.Length * NativeBytesPerCharacter);
250 } else if (type.IsArray) {
251 throw new ArgumentException ("Only string and byte arrays can written as registry values");
252 } else {
253 throw new ArgumentException ("Type does not match the valueKind");
256 // handle the result codes
257 if (result != Win32ResultCode.Success)
259 GenerateException (result);
263 public void SetValue (RegistryKey rkey, string name, object value)
265 Type type = value.GetType ();
266 int result;
267 IntPtr handle = GetHandle (rkey);
269 if (type == typeof (int)) {
270 int rawValue = (int)value;
271 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize);
272 } else if (type == typeof (byte[])) {
273 byte[] rawValue = (byte[]) value;
274 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
275 } else if (type == typeof (string[])) {
276 string[] vals = (string[]) value;
277 StringBuilder fullStringValue = new StringBuilder ();
278 foreach (string v in vals)
280 fullStringValue.Append (v);
281 fullStringValue.Append ('\0');
283 fullStringValue.Append ('\0');
285 byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
287 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length);
288 } else if (type.IsArray) {
289 throw new ArgumentException ("Only string and byte arrays can written as registry values");
290 } else {
291 string rawValue = String.Format ("{0}{1}", value, '\0');
292 result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.String, rawValue,
293 rawValue.Length * NativeBytesPerCharacter);
296 if (result == Win32ResultCode.MarkedForDeletion)
297 throw RegistryKey.CreateMarkedForDeletionException ();
299 // handle the result codes
300 if (result != Win32ResultCode.Success)
302 GenerateException (result);
306 /// <summary>
307 /// Get a binary value.
308 /// </summary>
309 private int GetBinaryValue (RegistryKey rkey, string name, RegistryValueKind type, out byte[] data, int size)
311 byte[] internalData = new byte [size];
312 IntPtr handle = GetHandle (rkey);
313 int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
314 data = internalData;
315 return result;
319 // Arbitrary max size for key/values names that can be fetched.
320 // .NET framework SDK docs say that the max name length that can
321 // be used is 255 characters, we'll allow for a bit more.
322 const int BufferMaxLength = 1024;
324 public int SubKeyCount (RegistryKey rkey)
326 int index;
327 StringBuilder stringBuffer = new StringBuilder (BufferMaxLength);
328 IntPtr handle = GetHandle (rkey);
330 for (index = 0; true; index ++) {
331 int result = RegEnumKey (handle, index, stringBuffer,
332 stringBuffer.Capacity);
334 if (result == Win32ResultCode.MarkedForDeletion)
335 throw RegistryKey.CreateMarkedForDeletionException ();
337 if (result == Win32ResultCode.Success)
338 continue;
340 if (result == Win32ResultCode.NoMoreEntries)
341 break;
343 // something is wrong!!
344 GenerateException (result);
346 return index;
349 public int ValueCount (RegistryKey rkey)
351 int index, result, bufferCapacity;
352 RegistryValueKind type;
353 StringBuilder buffer = new StringBuilder (BufferMaxLength);
355 IntPtr handle = GetHandle (rkey);
356 for (index = 0; true; index ++) {
357 type = 0;
358 bufferCapacity = buffer.Capacity;
359 result = RegEnumValue (handle, index,
360 buffer, ref bufferCapacity,
361 IntPtr.Zero, ref type,
362 IntPtr.Zero, IntPtr.Zero);
364 if (result == Win32ResultCode.MarkedForDeletion)
365 throw RegistryKey.CreateMarkedForDeletionException ();
367 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
368 continue;
370 if (result == Win32ResultCode.NoMoreEntries)
371 break;
373 // something is wrong
374 GenerateException (result);
376 return index;
379 public RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName)
381 IntPtr handle = new IntPtr ((int) hKey);
383 IntPtr keyHandle;
384 int result = RegConnectRegistry (machineName, handle, out keyHandle);
385 if (result != Win32ResultCode.Success)
386 GenerateException (result);
388 return new RegistryKey (hKey, keyHandle, true);
391 public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
393 int access = OpenRegKeyRead;
394 if (writable) access |= OpenRegKeyWrite;
395 IntPtr handle = GetHandle (rkey);
397 IntPtr subKeyHandle;
398 int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
400 if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
401 return null;
403 if (result != Win32ResultCode.Success)
404 GenerateException (result);
406 return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
409 public void Flush (RegistryKey rkey)
411 if (!IsHandleValid (rkey))
412 return;
413 IntPtr handle = GetHandle (rkey);
414 RegFlushKey (handle);
417 public void Close (RegistryKey rkey)
419 if (!IsHandleValid (rkey))
420 return;
421 IntPtr handle = GetHandle (rkey);
422 RegCloseKey (handle);
425 public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
427 IntPtr handle = GetHandle (rkey);
428 IntPtr subKeyHandle;
429 int result = RegCreateKey (handle , keyName, out subKeyHandle);
431 if (result == Win32ResultCode.MarkedForDeletion)
432 throw RegistryKey.CreateMarkedForDeletionException ();
434 if (result != Win32ResultCode.Success) {
435 GenerateException (result);
438 return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
439 true);
442 public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
444 IntPtr handle = GetHandle (rkey);
445 int result = RegDeleteKey (handle, keyName);
447 if (result == Win32ResultCode.FileNotFound) {
448 if (shouldThrowWhenKeyMissing)
449 throw new ArgumentException ("key " + keyName);
450 return;
453 if (result != Win32ResultCode.Success)
454 GenerateException (result);
457 public void DeleteValue (RegistryKey rkey, string value, bool shouldThrowWhenKeyMissing)
459 IntPtr handle = GetHandle (rkey);
460 int result = RegDeleteValue (handle, value);
462 if (result == Win32ResultCode.MarkedForDeletion)
463 return;
465 if (result == Win32ResultCode.FileNotFound){
466 if (shouldThrowWhenKeyMissing)
467 throw new ArgumentException ("value " + value);
468 return;
471 if (result != Win32ResultCode.Success)
472 GenerateException (result);
475 public string [] GetSubKeyNames (RegistryKey rkey)
477 IntPtr handle = GetHandle (rkey);
478 StringBuilder buffer = new StringBuilder (BufferMaxLength);
479 ArrayList keys = new ArrayList ();
481 for (int index = 0; true; index ++) {
482 int result = RegEnumKey (handle, index, buffer, buffer.Capacity);
484 if (result == Win32ResultCode.Success) {
485 keys.Add (buffer.ToString ());
486 buffer.Length = 0;
487 continue;
490 if (result == Win32ResultCode.NoMoreEntries)
491 break;
493 // should not be here!
494 GenerateException (result);
496 return (string []) keys.ToArray (typeof(String));
500 public string [] GetValueNames (RegistryKey rkey)
502 IntPtr handle = GetHandle (rkey);
503 ArrayList values = new ArrayList ();
505 for (int index = 0; true; index ++)
507 StringBuilder buffer = new StringBuilder (BufferMaxLength);
508 int bufferCapacity = buffer.Capacity;
509 RegistryValueKind type = 0;
511 int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
512 IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
514 if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData) {
515 values.Add (buffer.ToString ());
516 continue;
519 if (result == Win32ResultCode.NoMoreEntries)
520 break;
522 if (result == Win32ResultCode.MarkedForDeletion)
523 throw RegistryKey.CreateMarkedForDeletionException ();
525 GenerateException (result);
528 return (string []) values.ToArray (typeof(String));
531 /// <summary>
532 /// convert a win32 error code into an appropriate exception.
533 /// </summary>
534 private void GenerateException (int errorCode)
536 switch (errorCode) {
537 case Win32ResultCode.FileNotFound:
538 case Win32ResultCode.InvalidParameter:
539 throw new ArgumentException ();
540 case Win32ResultCode.AccessDenied:
541 throw new SecurityException ();
542 case Win32ResultCode.NetworkPathNotFound:
543 throw new IOException ("The network path was not found.");
544 default:
545 // unidentified system exception
546 throw new SystemException ();
550 public string ToString (RegistryKey rkey)
552 return rkey.Name;
555 /// <summary>
556 /// utility: Combine the sub key name to the current name to produce a
557 /// fully qualified sub key name.
558 /// </summary>
559 internal static string CombineName (RegistryKey rkey, string localName)
561 return String.Concat (rkey.Name, "\\", localName);
566 #endif // NET_2_1