2 // Microsoft.Win32/IRegistryApi.cs
5 // Miguel de Icaza (miguel@gnome.org)
7 // (C) 2005 Novell, Inc (http://www.novell.com)
10 // Someone could the same subkey twice: once read/write once readonly,
11 // currently since we use a unique hash based on the file name, we are unable
12 // to have two versions of the same key and hence unable to throw an exception
13 // if the user tries to write to a read-only key.
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System.Collections;
41 using System.Runtime.InteropServices;
42 using System.Reflection;
43 using System.Security;
44 using System.Threading;
46 namespace Microsoft.Win32 {
49 static Hashtable key_to_handler = new Hashtable ();
50 static Hashtable dir_to_key = new Hashtable ();
54 public Hashtable values;
58 KeyHandler (RegistryKey rkey, string basedir)
60 if (!Directory.Exists (basedir)){
62 Directory.CreateDirectory (basedir);
63 } catch (Exception e){
64 Console.Error.WriteLine ("KeyHandler error while creating directory {0}:\n{1}", basedir, e);
68 file = Path.Combine (Dir, "values.xml");
74 values = new Hashtable ();
75 if (!File.Exists (file))
79 using (FileStream fs = File.OpenRead (file)){
80 StreamReader r = new StreamReader (fs);
81 string xml = r.ReadToEnd ();
85 SecurityElement tree = SecurityElement.FromString (xml);
86 if (tree.Tag == "values"){
87 foreach (SecurityElement value in tree.Children){
88 if (value.Tag == "value"){
94 } catch (Exception e){
95 Console.Error.WriteLine ("While loading registry key at {0}: {1}", file, e);
100 void LoadKey (SecurityElement se)
102 Hashtable h = se.Attributes;
104 string name = (string) h ["name"];
107 string type = (string) h ["type"];
113 values [name] = Int32.Parse (se.Text);
116 Convert.FromBase64String (se.Text);
119 values [name] = se.Text;
122 ArrayList sa = new ArrayList ();
123 if (se.Children != null){
124 foreach (SecurityElement stre in se.Children){
128 values [name] = sa.ToArray (typeof (string));
132 // We ignore individual errors in the file.
136 public RegistryKey Ensure (RegistryKey rkey, string extra)
138 lock (typeof (KeyHandler)){
139 string f = Path.Combine (Dir, extra);
140 if (dir_to_key.Contains (f))
141 return (RegistryKey) dir_to_key [f];
143 KeyHandler kh = new KeyHandler (rkey, f);
144 RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
145 key_to_handler [rk] = kh;
151 public RegistryKey Probe (RegistryKey rkey, string extra, bool write)
153 lock (typeof (KeyHandler)){
154 string f = Path.Combine (Dir, extra);
155 if (dir_to_key.Contains (f))
156 return (RegistryKey) dir_to_key [f];
157 Console.WriteLine ("Trying: " + f);
158 if (Directory.Exists (f)){
159 KeyHandler kh = new KeyHandler (rkey, f);
160 RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
162 key_to_handler [rk] = kh;
169 static string CombineName (RegistryKey rkey, string extra)
171 if (extra.IndexOf ('/') != -1)
172 extra = extra.Replace ('/', '\\');
174 return String.Concat (rkey.Name, "\\", extra);
177 public static KeyHandler Lookup (RegistryKey rkey)
179 lock (typeof (KeyHandler)){
180 KeyHandler k = (KeyHandler) key_to_handler [rkey];
184 RegistryHive x = (RegistryHive) rkey.Data;
186 case RegistryHive.ClassesRoot:
187 case RegistryHive.CurrentConfig:
188 case RegistryHive.CurrentUser:
189 case RegistryHive.DynData:
190 case RegistryHive.LocalMachine:
191 case RegistryHive.PerformanceData:
192 case RegistryHive.Users:
193 string d = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".mono/registry");
194 d = Path.Combine (d, x.ToString ());
196 k = new KeyHandler (rkey, d);
197 key_to_handler [rkey] = k;
200 throw new Exception ("Unknown RegistryHive");
202 key_to_handler [rkey] = k;
207 public static void Drop (RegistryKey rkey)
209 KeyHandler k = (KeyHandler) key_to_handler [rkey];
212 dir_to_key.Remove (k.Dir);
213 key_to_handler.Remove (rkey);
216 public static void Drop (string dir)
218 if (dir_to_key.Contains (dir)){
219 key_to_handler.Remove (dir_to_key [dir]);
220 dir_to_key.Remove (dir);
224 public void SetValue (string name, object value)
226 values [name] = value;
232 lock (typeof (KeyHandler)){
236 new Timer (DirtyTimeout, null, 3000, Timeout.Infinite);
240 public void DirtyTimeout (object state)
247 lock (typeof (KeyHandler)){
260 if (!File.Exists (file) && values.Count == 0)
263 SecurityElement se = new SecurityElement ("values");
265 foreach (DictionaryEntry de in values){
266 object val = de.Value;
267 SecurityElement value = new SecurityElement ("value");
268 value.AddAttribute ("name", (string) de.Key);
271 value.AddAttribute ("type", "string");
272 value.Text = (string) val;
273 } else if (val is int){
274 value.AddAttribute ("type", "int");
275 value.Text = val.ToString ();
276 } else if (val is byte []){
277 value.AddAttribute ("type", "bytearray");
278 value.Text = Convert.ToBase64String ((byte[]) val);
279 } else if (val is string []){
280 value.AddAttribute ("type", "string-array");
282 foreach (string ss in (string[]) val){
283 SecurityElement str = new SecurityElement ("string");
285 value.AddChild (str);
292 using (FileStream fs = File.Create (file)){
293 StreamWriter sw = new StreamWriter (fs);
295 sw.Write (se.ToString ());
298 } catch (Exception e){
299 Console.Error.WriteLine ("When saving {0} got {1}", file, e);
304 internal class UnixRegistryApi : IRegistryApi {
306 static string ToUnix (string keyname)
308 if (keyname.IndexOf ('\\') != -1)
309 keyname = keyname.Replace ('\\', '/');
310 return keyname.ToLower ();
313 public RegistryKey CreateSubKey (RegistryKey rkey, string keyname)
315 KeyHandler self = KeyHandler.Lookup (rkey);
316 return self.Ensure (rkey, ToUnix (keyname));
319 public RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writtable)
321 KeyHandler self = KeyHandler.Lookup (rkey);
322 return self.Probe (rkey, ToUnix (keyname), writtable);
325 public void Flush (RegistryKey rkey)
327 KeyHandler self = KeyHandler.Lookup (rkey);
331 public void Close (RegistryKey rkey)
333 KeyHandler.Drop (rkey);
336 public object GetValue (RegistryKey rkey, string name, bool return_default_value, object default_value)
338 KeyHandler self = KeyHandler.Lookup (rkey);
340 if (self.values.Contains (name))
341 return self.values [name];
342 if (return_default_value)
343 return default_value;
347 public void SetValue (RegistryKey rkey, string name, object value)
349 if (!((value is int) || (value is string) || (value is string []) || (value is byte [])))
350 throw new ArgumentException ("The value is not int, string, string[] or byte[]", "value");
352 KeyHandler self = KeyHandler.Lookup (rkey);
353 self.SetValue (name, value);
356 public int SubKeyCount (RegistryKey rkey)
358 KeyHandler self = KeyHandler.Lookup (rkey);
360 return Directory.GetDirectories (self.Dir).Length;
363 public int ValueCount (RegistryKey rkey)
365 KeyHandler self = KeyHandler.Lookup (rkey);
367 return self.values.Keys.Count;
370 public void DeleteValue (RegistryKey rkey, string value, bool throw_if_missing)
372 KeyHandler self = KeyHandler.Lookup (rkey);
374 foreach (DictionaryEntry de in self.values){
375 if ((string)de.Value == value){
376 self.values.Remove (de.Key);
380 if (throw_if_missing)
381 throw new ArgumentException ("the given value does not exist", "value");
384 public void DeleteKey (RegistryKey rkey, string keyname, bool throw_if_missing)
386 KeyHandler self = KeyHandler.Lookup (rkey);
387 string dir = Path.Combine (self.Dir, keyname);
389 if (Directory.Exists (dir)){
390 Directory.Delete (dir, true);
391 KeyHandler.Drop (dir);
392 } else if (throw_if_missing)
393 throw new ArgumentException ("the given value does not exist", "value");
396 public string [] GetSubKeyNames (RegistryKey rkey)
398 KeyHandler self = KeyHandler.Lookup (rkey);
399 return Directory.GetDirectories (self.Dir);
402 public string [] GetValueNames (RegistryKey rkey)
404 KeyHandler self = KeyHandler.Lookup (rkey);
405 ICollection keys = self.values.Keys;
407 string [] vals = new string [keys.Count];
408 keys.CopyTo (vals, 0);
412 public string ToString (RegistryKey rkey)