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