PageRenderTime 26ms CodeModel.GetById 2ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/IronPython_Main/Languages/IronPython/IronPython.Modules/_winreg.cs

#
C# | 549 lines | 426 code | 88 blank | 35 comment | 98 complexity | 465515db48a42c90e69192199099bc0c MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Apache License, Version 2.0, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16using System;
 17using System.Collections.Generic;
 18using System.ComponentModel;
 19using System.Diagnostics;
 20using System.IO;
 21using System.Runtime.InteropServices;
 22using System.Security;
 23using System.Security.AccessControl;
 24using System.Text;
 25
 26using Microsoft.Win32;
 27using Microsoft.Win32.SafeHandles;
 28
 29using IronPython.Runtime;
 30using IronPython.Runtime.Exceptions;
 31using IronPython.Runtime.Operations;
 32using IronPython.Runtime.Types;
 33
 34#if CLR2
 35using Microsoft.Scripting.Math;
 36#else
 37using System.Numerics;
 38#endif
 39
 40#if !SILVERLIGHT && !CLR2 //Registry not available in silverlight and we require .NET 4.0 APIs for implementing this.
 41
 42[assembly: PythonModule("_winreg", typeof(IronPython.Modules.PythonWinReg))]
 43namespace IronPython.Modules {
 44    public static class PythonWinReg {
 45        public const string __doc__ = "Provides access to the Windows registry.";
 46
 47        public static PythonType error = PythonExceptions.WindowsError;
 48
 49        #region Constants
 50
 51        public static BigInteger HKEY_CLASSES_ROOT = 0x80000000L;
 52        public static BigInteger HKEY_CURRENT_USER = 0x80000001L;
 53        public static BigInteger HKEY_LOCAL_MACHINE = 0x80000002L;
 54        public static BigInteger HKEY_USERS = 0x80000003L;
 55        public static BigInteger HKEY_PERFORMANCE_DATA = 0x80000004L;
 56        public static BigInteger HKEY_CURRENT_CONFIG = 0x80000005L;
 57        public static BigInteger HKEY_DYN_DATA = 0x80000006L;
 58
 59        public const int KEY_QUERY_VALUE = 0X1;
 60        public const int KEY_SET_VALUE = 0X2;
 61        public const int KEY_CREATE_SUB_KEY = 0X4;
 62        public const int KEY_ENUMERATE_SUB_KEYS = 0X8;
 63        public const int KEY_NOTIFY = 0X10;
 64        public const int KEY_CREATE_LINK = 0X20;
 65
 66        public const int KEY_ALL_ACCESS = 0XF003F;
 67        public const int KEY_EXECUTE = 0X20019;
 68        public const int KEY_READ = 0X20019;
 69        public const int KEY_WRITE = 0X20006;
 70
 71        public const int REG_CREATED_NEW_KEY = 0X1;
 72        public const int REG_OPENED_EXISTING_KEY = 0X2;
 73
 74        public const int REG_NONE = 0X0;
 75        public const int REG_SZ = 0X1;
 76        public const int REG_EXPAND_SZ = 0X2;
 77        public const int REG_BINARY = 0X3;
 78        public const int REG_DWORD = 0X4;
 79        public const int REG_DWORD_LITTLE_ENDIAN = 0X4;
 80        public const int REG_DWORD_BIG_ENDIAN = 0X5;
 81        public const int REG_LINK = 0X6;
 82        public const int REG_MULTI_SZ = 0X7;
 83        public const int REG_RESOURCE_LIST = 0X8;
 84        public const int REG_FULL_RESOURCE_DESCRIPTOR = 0X9;
 85        public const int REG_RESOURCE_REQUIREMENTS_LIST = 0XA;
 86
 87        public const int REG_NOTIFY_CHANGE_NAME = 0X1;
 88        public const int REG_NOTIFY_CHANGE_ATTRIBUTES = 0X2;
 89        public const int REG_NOTIFY_CHANGE_LAST_SET = 0X4;
 90        public const int REG_NOTIFY_CHANGE_SECURITY = 0X8;
 91
 92        public const int REG_OPTION_RESERVED = 0X0;
 93        public const int REG_OPTION_NON_VOLATILE = 0X0;
 94        public const int REG_OPTION_VOLATILE = 0X1;
 95        public const int REG_OPTION_CREATE_LINK = 0X2;
 96        public const int REG_OPTION_BACKUP_RESTORE = 0X4;
 97        public const int REG_OPTION_OPEN_LINK = 0X8;
 98
 99        public const int REG_NO_LAZY_FLUSH = 0X4;
100        public const int REG_REFRESH_HIVE = 0X2;
101        public const int REG_LEGAL_CHANGE_FILTER = 0XF;
102        public const int REG_LEGAL_OPTION = 0XF;
103        public const int REG_WHOLE_HIVE_VOLATILE = 0X1;
104
105        #endregion
106
107        #region Module Methods
108
109        public static void CloseKey(HKEYType key) {
110            key.Close();
111        }
112
113        public static HKEYType CreateKey(object key, string subKeyName) {
114            HKEYType rootKey = GetRootKey(key);
115
116            //if key is a system key and no subkey is specified return that.
117            if (key is BigInteger && string.IsNullOrEmpty(subKeyName))
118                return rootKey;
119            
120            HKEYType subKey = new HKEYType(rootKey.GetKey().CreateSubKey(subKeyName));
121            return subKey;
122        }
123
124
125        public static HKEYType CreateKeyEx(object key, string subKeyName, int res, int sam) {
126            HKEYType rootKey = GetRootKey(key);
127
128            //if key is a system key and no subkey is specified return that.
129            if (key is BigInteger && string.IsNullOrEmpty(subKeyName))
130                return rootKey;
131
132            SafeRegistryHandle handle;
133            int disposition;
134            
135            int result = RegCreateKeyEx(
136                rootKey.GetKey().Handle,
137                subKeyName,
138                0,
139                null,
140                RegistryOptions.None,
141                (RegistryRights)sam,
142                IntPtr.Zero,
143                out handle,
144                out disposition
145            );
146            if (result != ERROR_SUCCESS) {
147                throw PythonExceptions.CreateThrowable(error, result, CTypes.FormatError(result));
148            }
149
150            return new HKEYType(RegistryKey.FromHandle(handle));
151        }
152
153        [DllImport("advapi32.dll", SetLastError = true)]
154        static extern int RegCreateKeyEx(
155                    SafeRegistryHandle hKey,
156                    string lpSubKey,
157                    int Reserved,
158                    string lpClass,
159                    RegistryOptions dwOptions,
160                    RegistryRights samDesired,
161                    IntPtr lpSecurityAttributes,
162                    out SafeRegistryHandle phkResult,
163                    out int lpdwDisposition);
164
165        [DllImport("advapi32.dll", SetLastError = true, CharSet=CharSet.Auto)]
166        static extern int RegQueryValueEx(
167              SafeRegistryHandle hKey,
168              string lpValueName,
169              IntPtr lpReserved,
170              out int lpType,
171              byte[] lpData,
172              ref uint lpcbData
173            );
174
175
176        public static void DeleteKey(object key, string subKeyName) {
177            HKEYType rootKey = GetRootKey(key);
178            if (key is BigInteger && string.IsNullOrEmpty(subKeyName))
179                throw new InvalidCastException("DeleteKey() argument 2 must be string, not None");
180
181            try {
182                rootKey.GetKey().DeleteSubKey(subKeyName);
183            } catch (ArgumentException e) {
184                throw new ExternalException(e.Message);
185            }
186        }
187
188        public static void DeleteValue(object key, string value) {
189            HKEYType rootKey = GetRootKey(key);
190
191            rootKey.GetKey().DeleteValue(value, true);
192        }
193
194        public static string EnumKey(object key, int index) {
195            HKEYType rootKey = GetRootKey(key);
196            if (index >= rootKey.GetKey().SubKeyCount) {
197                throw PythonExceptions.CreateThrowable(PythonExceptions.WindowsError, PythonExceptions._WindowsError.ERROR_BAD_COMMAND, "No more data is available");
198            }
199            return rootKey.GetKey().GetSubKeyNames()[index];
200        }
201
202        const int ERROR_MORE_DATA = 234;
203        const int ERROR_SUCCESS = 0;
204
205        public static PythonTuple EnumValue(object key, int index) {
206            HKEYType rootKey = GetRootKey(key);
207            if (index >= rootKey.GetKey().ValueCount) {
208                throw PythonExceptions.CreateThrowable(PythonExceptions.WindowsError, PythonExceptions._WindowsError.ERROR_BAD_COMMAND, "No more data is available");
209            }
210
211            var nativeRootKey = rootKey.GetKey();
212            string valueName = nativeRootKey.GetValueNames()[index];
213
214            int valueKind;
215            object value;
216            QueryValueExImpl(nativeRootKey, valueName, out valueKind, out value);
217            return PythonTuple.MakeTuple(valueName, value, valueKind);
218        }
219
220        private static void QueryValueExImpl(RegistryKey nativeRootKey, string valueName, out int valueKind, out object value) {
221            valueKind = 0;
222            int dwRet;
223            byte[] data = new byte[128];
224            uint length = (uint)data.Length;
225            // query the size first, reading the data as we query...
226            dwRet = RegQueryValueEx(nativeRootKey.Handle, valueName, IntPtr.Zero, out valueKind, data, ref length);
227            while (dwRet == ERROR_MORE_DATA) {
228                data = new byte[data.Length * 2];
229                length = (uint)data.Length;
230                dwRet = RegQueryValueEx(nativeRootKey.Handle, valueName, IntPtr.Zero, out valueKind, data, ref length);
231            }
232
233            // convert the result into a Python object
234
235            switch (valueKind) {
236                case REG_MULTI_SZ:
237                    List list = new List();
238                    int curIndex = 0;
239                    while (curIndex < length) {
240                        for (int dataIndex = curIndex; dataIndex < length; dataIndex += 2) {
241                            if (data[dataIndex] == 0 && data[dataIndex + 1] == 0) {
242                                // got a full string
243                                list.Add(ExtractString(data, curIndex, dataIndex));
244                                curIndex = dataIndex + 2;
245
246                                if (curIndex + 2 <= length && data[curIndex] == 0 && data[curIndex + 1] == 0) {
247                                    // double null terminated
248                                    curIndex = data.Length;
249                                    break;
250                                }
251                            }
252                        }
253
254                        if (curIndex != data.Length) {
255                            // not null terminated
256                            list.Add(ExtractString(data, curIndex, data.Length));
257                        }
258                    }
259                    value = list;
260                    break;
261                case REG_BINARY:
262                    value = PythonOps.MakeString(data, (int)length);
263                    break;
264                case REG_EXPAND_SZ:
265                case REG_SZ:
266                    if (length >= 2 && data[length - 1] == 0 && data[length - 2] == 0) {
267                        value = ExtractString(data, 0, (int)length - 2);
268                    } else {
269                        value = ExtractString(data, 0, (int)length);
270                    }
271                    break;
272                case REG_DWORD:
273                    if (BitConverter.IsLittleEndian) {
274                        value = ((data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0]);
275                    } else {
276                        value = ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
277                    }
278                    break;
279                default:
280                    value = null;
281                    break;
282            }
283
284        }
285
286        private static string ExtractString(byte[] data, int start, int end) {
287            if (end <= start) {
288                return String.Empty;
289            }
290            char[] chars = new char[(end - start) / 2];
291            for (int i = 0; i < chars.Length; i++) {
292                chars[i] = (char)((data[i*2 + start]) | (data[i*2 + start + 1] << 8));
293            }
294            return new string(chars);
295        }
296
297        public static void FlushKey(object key) {
298            HKEYType rootKey = GetRootKey(key);
299            rootKey.GetKey().Flush();
300        }
301
302        public static HKEYType OpenKey(object key, string subKeyName) {
303            return OpenKey(key, subKeyName, 0, KEY_READ);
304        }
305
306        public static HKEYType OpenKey(object key, string subKeyName, [DefaultParameterValue(0)]int res, [DefaultParameterValue(KEY_READ)]int sam) {
307            HKEYType rootKey = GetRootKey(key);
308            RegistryKey newKey = null;
309
310            // I'm assuming that the masks that CPy uses are the same as the Win32 API one mentioned here-
311            // http://msdn2.microsoft.com/en-us/library/ms724878(VS.85).aspx
312
313            // KEY_WRITE is a combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY. We'll open with write access
314            // if any of this is set.
315            // KEY_READ is a combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS and KEY_NOTIFY. We'll open
316            // with read access for all of these. 
317
318            var nativeRootKey = rootKey.GetKey();
319            try {
320                if ((sam & KEY_SET_VALUE) == KEY_SET_VALUE ||
321                    (sam & KEY_CREATE_SUB_KEY) == KEY_CREATE_SUB_KEY) {
322                        if (res != 0) {
323                            newKey = nativeRootKey.OpenSubKey(subKeyName, RegistryKeyPermissionCheck.Default, (RegistryRights)res);
324                        } else {
325                            newKey = nativeRootKey.OpenSubKey(subKeyName, true);
326                        }
327                } else if ((sam & KEY_QUERY_VALUE) == KEY_QUERY_VALUE ||
328                           (sam & KEY_ENUMERATE_SUB_KEYS) == KEY_ENUMERATE_SUB_KEYS ||
329                           (sam & KEY_NOTIFY) == KEY_NOTIFY) {
330                               if (res != 0) {
331                                   newKey = nativeRootKey.OpenSubKey(subKeyName, RegistryKeyPermissionCheck.ReadSubTree, (RegistryRights)res);
332                               } else {
333                                   newKey = nativeRootKey.OpenSubKey(subKeyName, false);
334                               }
335                } else {
336                    throw new Win32Exception("Unexpected mode");
337                }
338            } catch (SecurityException) {
339                throw PythonExceptions.CreateThrowable(PythonExceptions.WindowsError, PythonExceptions._WindowsError.ERROR_ACCESS_DENIED, "Access is denied");
340            }
341
342
343            if (newKey == null) {
344                throw PythonExceptions.CreateThrowable(PythonExceptions.WindowsError, PythonExceptions._WindowsError.ERROR_FILE_NOT_FOUND, "The system cannot find the file specified");
345            }
346
347            return new HKEYType(newKey);
348        }
349
350        public static HKEYType OpenKeyEx(object key, string subKeyName, [DefaultParameterValue(0)]int res, [DefaultParameterValue(KEY_READ)]int sam) {
351            return OpenKey(key, subKeyName, res, sam);
352        }
353
354        public static PythonTuple QueryInfoKey(object key) {
355            HKEYType rootKey = null;
356            //The key can also be a handle. If it is, then retrieve it from the cache.
357            if (key is int) {
358                if (HKeyHandleCache.cache.ContainsKey((int)key)) {
359                    if (HKeyHandleCache.cache[(int)key].IsAlive) {
360                        rootKey = HKeyHandleCache.cache[(int)key].Target as HKEYType;
361                    }
362                }
363            } else {
364                rootKey = GetRootKey(key);
365            }
366
367            if (rootKey == null) {
368                throw PythonExceptions.CreateThrowable(PythonExceptions.EnvironmentError, "key has been closed");
369            }
370
371            try {
372                var nativeRootKey = rootKey.GetKey();
373                return PythonTuple.MakeTuple(nativeRootKey.SubKeyCount, nativeRootKey.ValueCount, 0);
374            } catch (ObjectDisposedException e) {
375                throw new ExternalException(e.Message);
376            }
377        }
378
379        public static object QueryValue(object key, string subKeyName) {
380            HKEYType pyKey = OpenKey(key, subKeyName);
381            return pyKey.GetKey().GetValue(null);
382        }
383
384        public static PythonTuple QueryValueEx(object key, string valueName) {
385            HKEYType rootKey = GetRootKey(key);
386
387            int valueKind;
388            object value;
389            QueryValueExImpl(rootKey.GetKey(), valueName, out valueKind, out value);
390
391            return PythonTuple.MakeTuple(value, valueKind);
392        }
393
394        public static void SetValue(object key, string subKeyName, int type, string value) {
395            HKEYType pyKey = CreateKey(key, subKeyName);
396            pyKey.GetKey().SetValue(null, value);
397        }
398
399        public static void SetValueEx(object key, string valueName, int reserved, int type, object value) {
400            HKEYType rootKey = GetRootKey(key);
401            RegistryValueKind regKind = (RegistryValueKind)type;
402
403            if (regKind == RegistryValueKind.MultiString) {
404                int size = ((List)value)._size;
405                string[] strArray = new string[size];
406                Array.Copy(((List)value)._data, strArray, size);
407                rootKey.GetKey().SetValue(valueName, strArray, regKind);
408            } else if (regKind == RegistryValueKind.Binary) {
409                byte[] byteArr = null;
410                if (value is string) {
411                    string strValue = value as string;
412                    ASCIIEncoding encoding = new ASCIIEncoding();
413                    byteArr = encoding.GetBytes(strValue);
414                }
415                rootKey.GetKey().SetValue(valueName, byteArr, regKind);
416            } else {
417                rootKey.GetKey().SetValue(valueName, value, regKind);
418            }
419
420        }
421
422        public static HKEYType ConnectRegistry(string computerName, BigInteger key) {
423            if (string.IsNullOrEmpty(computerName))
424                computerName = string.Empty;
425
426            RegistryKey newKey;
427            try {
428                newKey = RegistryKey.OpenRemoteBaseKey(MapSystemKey(key), computerName);
429            }catch(IOException ioe) {
430                throw PythonExceptions.CreateThrowable(PythonExceptions.WindowsError, PythonExceptions._WindowsError.ERROR_BAD_NETPATH, ioe.Message);
431            } catch (Exception e) {
432                throw new ExternalException(e.Message);
433            }
434            return new HKEYType(newKey);
435        }
436        #endregion
437
438        #region Helpers
439        private static HKEYType GetRootKey(object key) {
440            HKEYType rootKey;
441            rootKey = key as HKEYType;
442            if (rootKey == null) {
443                if (key is BigInteger) {
444                    rootKey = new HKEYType(RegistryKey.OpenRemoteBaseKey(MapSystemKey((BigInteger)key), string.Empty));
445                } else {
446                    throw new InvalidCastException("The object is not a PyHKEY object");
447                }
448            }
449            return rootKey;
450        }
451
452        private static RegistryHive MapSystemKey(BigInteger hKey) {
453            if (hKey == HKEY_CLASSES_ROOT)
454                return RegistryHive.ClassesRoot;
455            else if (hKey == HKEY_CURRENT_CONFIG)
456                return RegistryHive.CurrentConfig;
457            else if (hKey == HKEY_CURRENT_USER)
458                return RegistryHive.CurrentUser;
459            else if (hKey == HKEY_DYN_DATA)
460                return RegistryHive.DynData;
461            else if (hKey == HKEY_LOCAL_MACHINE)
462                return RegistryHive.LocalMachine;
463            else if (hKey == HKEY_PERFORMANCE_DATA)
464                return RegistryHive.PerformanceData;
465            else if (hKey == HKEY_USERS)
466                return RegistryHive.Users;
467            else
468                throw new ValueErrorException("Unknown system key");
469        }
470
471        private static int MapRegistryValueKind(RegistryValueKind registryValueKind) {
472            return (int)registryValueKind;
473        }
474
475        #endregion
476
477
478        [PythonType]
479        public class HKEYType : IDisposable {
480            private RegistryKey key;
481            internal HKEYType(RegistryKey key) {
482                this.key = key;
483                HKeyHandleCache.cache[key.GetHashCode()] = new WeakReference(this);
484            }
485
486            public void Close() {
487                lock (this) {
488                    if (key != null) {
489                        HKeyHandleCache.cache.Remove(key.GetHashCode());
490                        key.Close();
491                        key = null;
492                    }
493                }
494            }
495
496            public int Detach() {
497                return 0; //Can't keep handle after the object is destroyed.
498            }
499
500            public int handle {
501                get {
502                    lock (this) {
503                        if (key == null) {
504                            return 0;
505                        }
506                        return key.GetHashCode();
507                    }
508                }
509            }
510
511            public static implicit operator int(HKEYType hKey) {
512                return hKey.handle;
513            }
514
515            /// <summary>
516            /// Returns the underlying .NET RegistryKey
517            /// </summary>
518            /// <returns></returns>
519            [PythonHidden]
520            public RegistryKey GetKey() {
521                lock (this) {
522                    if (key == null) {
523                        throw PythonExceptions.CreateThrowable(PythonExceptions.EnvironmentError, "key has been closed");
524                    }
525                    return key;
526                }
527            }
528
529            #region IDisposable Members
530
531            void IDisposable.Dispose() {
532                Close();
533            }
534
535            #endregion
536        }
537    }
538
539    //CPython exposes the native handle for the registry keys as well. Since there is no .NET API to
540    //expose the native handle, we return the hashcode of the key as the "handle". To track these handles 
541    //and return the right RegistryKey we maintain this cache of the generated handles.
542    internal static class HKeyHandleCache {
543        internal static Dictionary<int, WeakReference> cache = new Dictionary<int, WeakReference>();
544
545    }
546
547}
548
549#endif