+2005-11-12 Miguel de Icaza <miguel@novell.com>
+
+ * RegistryKey.cs: Add support for a Registry on Unix based on
+ files under ~/.mono/registry.
+
+ Vastly refactored the code, reworked the interface between the
+ frontend and the backends.
+
+ If "RegistryKey" was not sealed, things could have been a lot
+ cleaner.
+
2005-01-31 mei (mei@work.email.ne.jp)
* RegistryKey.cs: Fixes bug 70451: When the key doesn't exist, and
namespace Microsoft.Win32 {
internal interface IRegistryApi {
-
- int OpenRegKeyRead { get; }
- int OpenRegKeyWrite { get; }
-
-
- // type values for registry value data
- int RegStringType { get; }
- int RegEnvironmentString { get; }
- int RegBinaryType { get; }
- int RegDwordType { get; }
- int RegStringArrayType { get; }
-
- int RegCreateKey (IntPtr keyBase,
- string keyName, out IntPtr keyHandle);
-
- int RegCloseKey (IntPtr keyHandle);
-
- int RegFlushKey (IntPtr keyHandle);
-
- int RegOpenKeyEx (IntPtr keyBase,
- string keyName, IntPtr reserved, int access,
- out IntPtr keyHandle);
+ RegistryKey CreateSubKey (RegistryKey rkey, string keyname);
+ RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writtable);
+ void Flush (RegistryKey rkey);
+ void Close (RegistryKey rkey);
- int RegDeleteKey (IntPtr keyHandle,
- string valueName);
+ object GetValue (RegistryKey rkey, string name, bool return_default_value, object default_value);
+ void SetValue (RegistryKey rkey, string name, object value);
- int RegDeleteValue (IntPtr keyHandle,
- string valueName);
-
- int RegEnumKey (IntPtr keyBase, int index,
- [Out] byte[] nameBuffer, int bufferLength);
-
- int RegEnumValue (IntPtr keyBase,
- int index, StringBuilder nameBuffer,
- ref int nameLength, IntPtr reserved,
- ref int type, IntPtr data, IntPtr dataLength);
-
- int RegSetValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- StringBuilder data, int rawDataLength);
-
- int RegSetValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- string data, int rawDataLength);
-
- int RegSetValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- byte[] rawData, int rawDataLength);
-
- int RegSetValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- ref int data, int rawDataLength);
-
- int RegQueryValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- IntPtr zero, ref int dataSize);
+ int SubKeyCount (RegistryKey rkey);
+ int ValueCount (RegistryKey rkey);
- int RegQueryValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- [Out] byte[] data, ref int dataSize);
-
- int RegQueryValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- ref int data, ref int dataSize);
+ void DeleteValue (RegistryKey rkey, string value, bool throw_if_missing);
+ void DeleteKey (RegistryKey rkey, string keyName, bool throw_if_missing);
+ string [] GetSubKeyNames (RegistryKey rkey);
+ string [] GetValueNames (RegistryKey rkey);
+ string ToString (RegistryKey rkey);
}
}
/// </summary>
public sealed class RegistryKey : MarshalByRefObject, IDisposable
{
- const char NullChar = '\0';
+ //
+ // This represents the backend data, used when creating the
+ // RegistryKey object
+ //
+ public object Data;
- // Arbitrary max size for key/values names that can be fetched.
- // .NET framework SDK docs say that the max name length that can
- // be used is 255 characters, we'll allow for a bit more.
- const int BufferMaxLength = 1024;
-
- // FIXME must be a way to determin this dynamically?
- const int Int32ByteSize = 4;
-
- // FIXME this is hard coded on Mono, can it be determined dynamically?
- readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
-
- // FIXME this should be determined dynamically.
- // It will be used to decode some return strings
- // for which embeded '\0' must be preserved.
- readonly Encoding Decoder = Encoding.Unicode;
-
-
- IntPtr hkey; // the reg key handle
string qname; // the fully qualified registry key name
bool isRoot; // is the an instance of a root key?
- IRegistryApi reg_api;
+ static readonly IRegistryApi RegistryApi;
+
+ static RegistryKey ()
+ {
+ if (Path.DirectorySeparatorChar == '\\')
+ RegistryApi = new Win32RegistryApi ();
+ else
+ RegistryApi = new UnixRegistryApi ();
+ }
/// <summary>
/// Construct an instance of a root registry key entry.
/// </summary>
internal RegistryKey (RegistryHive hiveId, string keyName)
{
- hkey = new IntPtr ((int)hiveId);
+ Data = hiveId;
qname = keyName;
isRoot = true;
-
- InitRegistryApi ();
}
/// <summary>
/// Construct an instance of a registry key entry.
/// </summary>
- internal RegistryKey (IntPtr hkey, string keyName)
+ internal RegistryKey (object data, string keyName)
{
- this.hkey = hkey;
+ Data = data;
qname = keyName;
isRoot = false;
-
- InitRegistryApi ();
- }
-
- internal void InitRegistryApi ()
- {
- if (Path.DirectorySeparatorChar == '\\')
- reg_api = new Win32RegistryApi ();
- }
-
- private IRegistryApi RegistryApi {
- get {
- if (reg_api == null)
- throw new NotImplementedException ("The registry is" +
- " only available on Windows.");
- return reg_api;
- }
}
- /// <summary>
- /// Fetch the inetrnal registry key.
- /// </summary>
- private IntPtr Handle {
- get { return hkey; }
- }
-
-
#region PublicAPI
/// <summary>
/// </summary>
public void Flush()
{
- RegTrace (" +Flush");
- RegistryApi.RegFlushKey (Handle);
- RegTrace (" -Flush");
+ RegistryApi.Flush (this);
}
if (isRoot)
return;
- RegTrace (" +Close");
- RegistryApi.RegCloseKey (Handle);
- hkey = IntPtr.Zero;
- RegTrace (" -Close");
+ RegistryApi.Close (this);
+ Data = null;
}
/// </summary>
public int SubKeyCount {
get {
- RegTrace (" +SubKeyCount");
AssertKeyStillValid ();
-
- int index, result;
- byte[] stringBuffer = new byte [BufferMaxLength];
-
- for (index = 0; true; index ++)
- {
- result = RegistryApi.RegEnumKey (Handle, index,
- stringBuffer, BufferMaxLength);
-
- if (result == Win32ResultCode.Success)
- continue;
-
- if (result == Win32ResultCode.NoMoreEntries)
- break;
-
- // something is wrong!!
- RegTrace ("Win32Api::ReEnumKey result='{0}' name='{1}'",
- result, Name);
- GenerateException (result);
- }
-
- RegTrace (" -SubKeyCount");
- return index;
+
+ return RegistryApi.SubKeyCount (this);
}
}
/// </summary>
public int ValueCount {
get {
- RegTrace (" +ValueCount");
AssertKeyStillValid ();
-
- int index, result, type, bufferCapacity;
- StringBuilder buffer = new StringBuilder (BufferMaxLength);
-
- for (index = 0; true; index ++)
- {
- type = 0;
- bufferCapacity = buffer.Capacity;
- result = RegistryApi.RegEnumValue (Handle, index,
- buffer, ref bufferCapacity,
- IntPtr.Zero, ref type,
- IntPtr.Zero, IntPtr.Zero);
-
- if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
- continue;
-
- if (result == Win32ResultCode.NoMoreEntries)
- break;
-
- // something is wrong
- RegTrace ("Win32Api::RegEnumValue result='{0}' name='{1}'",
- result, Name);
- GenerateException (result);
- }
-
- RegTrace (" -ValueCount");
- return index;
+
+ return RegistryApi.ValueCount (this);
}
}
/// </summary>
public void SetValue (string name, object value)
{
- RegTrace (" +SetValue");
AssertKeyStillValid ();
if (value == null)
throw new ArgumentNullException ();
-
- Type type = value.GetType ();
- int result;
-
- if (type == typeof (int))
- {
- int rawValue = (int)value;
- result = RegistryApi.RegSetValueEx (Handle, name,
- IntPtr.Zero, RegistryApi.RegDwordType,
- ref rawValue, Int32ByteSize);
- }
- else if (type == typeof (byte[]))
- {
- byte[] rawValue = (byte[]) value;
- result = RegistryApi.RegSetValueEx (Handle, name,
- IntPtr.Zero, RegistryApi.RegBinaryType,
- rawValue, rawValue.Length);
- }
- else if (type == typeof (string[]))
- {
- string[] vals = (string[]) value;
- StringBuilder fullStringValue = new StringBuilder ();
- foreach (string v in vals)
- {
- fullStringValue.Append (v);
- fullStringValue.Append (NullChar);
- }
- fullStringValue.Append (NullChar);
-
- byte[] rawValue = Decoder.GetBytes (fullStringValue.ToString ());
-
- result = RegistryApi.RegSetValueEx (Handle, name,
- IntPtr.Zero, RegistryApi.RegStringArrayType,
- rawValue, rawValue.Length);
- }
- else if (type.IsArray)
- {
- throw new ArgumentException ("Only string and byte arrays can written as registry values");
- }
- else
- {
- string rawValue = String.Format ("{0}{1}", value, NullChar);
- result = RegistryApi.RegSetValueEx (Handle, name,
- IntPtr.Zero, RegistryApi.RegStringType,
- rawValue, rawValue.Length * NativeBytesPerCharacter);
- }
- // handle the result codes
- if (result != Win32ResultCode.Success)
- {
- RegTrace ("Win32Api::RegSetValueEx: result: {0}", result);
- GenerateException (result);
- }
+ if (isRoot)
+ throw new UnauthorizedAccessException ();
- RegTrace (" -SetValue");
+ RegistryApi.SetValue (this, name, value);
}
/// </summary>
public RegistryKey OpenSubKey (string keyName, bool writtable)
{
- RegTrace (" +OpenSubKey");
AssertKeyStillValid ();
AssertKeyNameNotNull (keyName);
-
- int access = RegistryApi.OpenRegKeyRead;
- if (writtable) access |= RegistryApi.OpenRegKeyWrite;
-
- IntPtr subKeyHandle;
- int result = RegistryApi.RegOpenKeyEx (Handle, keyName, IntPtr.Zero,
- access, out subKeyHandle);
- if (result == Win32ResultCode.FileNotFound)
- {
- RegTrace (" -OpenSubKey");
- return null;
- }
-
- if (result != Win32ResultCode.Success)
- {
- RegTrace ("Win32Api::RegOpenKeyEx result='{0}' key name='{1}'",
- result, CombineName (keyName));
- GenerateException (result);
- }
-
- RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (keyName));
- RegTrace (" -OpenSubKey");
- return subKey;
+ return RegistryApi.OpenSubKey (this, keyName, writtable);
}
/// </summary>
public object GetValue (string name)
{
- RegTrace (" +GetValue");
- object obj = GetValueImpl (name, false, null);
- RegTrace (" -GetValue");
- return obj;
+ return RegistryApi.GetValue (this, name, false, null);
}
/// </summary>
public object GetValue (string name, object defaultValue)
{
- RegTrace (" +GetValue");
- object obj = GetValueImpl (name, true, defaultValue);
- RegTrace (" -GetValue");
- return obj;
+ AssertKeyStillValid ();
+
+ return RegistryApi.GetValue (this, name, true, defaultValue);
}
/// <summary>
/// Create a sub key.
/// </summary>
- public RegistryKey CreateSubKey (string keyName)
+ [MonoTODO("RegistryPermission")]
+ public RegistryKey CreateSubKey (string subkey)
{
- RegTrace (" +CreateSubKey");
AssertKeyStillValid ();
- AssertKeyNameNotNull (keyName);
-
- IntPtr subKeyHandle;
- int result = RegistryApi.RegCreateKey (Handle , keyName, out subKeyHandle);
-
- if (result != Win32ResultCode.Success)
- {
- RegTrace ("Win32Api::RegCreateKey: result='{0}' key name='{1}'",
- result, CombineName (keyName));
- GenerateException (result);
- }
-
- RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (keyName));
- RegTrace (" -CreateSubKey");
- return subKey;
+ AssertKeyNameNotNull (subkey);
+ if (subkey.Length > 255)
+ throw new ArgumentException ("keyName length is larger than 255 characters", subkey);
+ return RegistryApi.CreateSubKey (this, subkey);
}
/// <summary>
/// Delete the specified subkey.
/// </summary>
- public void DeleteSubKey(string keyName, bool shouldThrowWhenKeyMissing)
+ public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
{
- RegTrace (" +DeleteSubKey");
AssertKeyStillValid ();
- AssertKeyNameNotNull (keyName);
-
- RegistryKey child = OpenSubKey (keyName);
+ AssertKeyNameNotNull (subkey);
+
+ RegistryKey child = OpenSubKey (subkey);
- if (child == null)
- {
- if (shouldThrowWhenKeyMissing)
- throw new ArgumentException ("key " + keyName);
- RegTrace (" -DeleteSubKey");
+ if (child == null) {
+ if (throwOnMissingSubKey)
+ throw new ArgumentException ("key missing: " + subkey, "subkey");
return;
}
- if (child.SubKeyCount > 0)
- throw new InvalidOperationException ("key " + keyName + " has sub keys");
-
- child.Close ();
-
- int result = RegistryApi.RegDeleteKey (Handle, keyName);
- if (result == Win32ResultCode.FileNotFound)
- {
- if (shouldThrowWhenKeyMissing)
- throw new ArgumentException ("key " + keyName);
- RegTrace (" -DeleteSubKey");
- return;
+ if (child.SubKeyCount > 0){
+ throw new InvalidOperationException ("key " + subkey + " has sub keys");
}
- if (result != Win32ResultCode.Success)
- {
- RegTrace ("Win32Api::RegDeleteKey: result='{0}' key name='{1}'",
- result, CombineName (keyName));
- GenerateException (result);
- }
+ child.Close ();
- RegTrace (" -DeleteSubKey");
+ RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
}
// Note: this is done by deleting sub-nodes recursively.
// The preformance is not very good. There may be a
// better way to implement this.
- RegTrace (" +DeleteSubKeyTree");
+
AssertKeyStillValid ();
AssertKeyNameNotNull (keyName);
RegistryKey child = OpenSubKey (keyName, true);
if (child == null)
- throw new ArgumentException ("key " + keyName);
+ throw new ArgumentException ("key " + keyName + " at " + Name);
child.DeleteChildKeysAndValues ();
child.Close ();
DeleteSubKey (keyName, false);
- RegTrace (" -DeleteSubKeyTree");
}
/// </summary>
public void DeleteValue(string value, bool shouldThrowWhenKeyMissing)
{
- RegTrace (" +DeleteValue");
AssertKeyStillValid ();
AssertKeyNameNotNull (value);
-
- int result = RegistryApi.RegDeleteValue (Handle, value);
-
- if (result == Win32ResultCode.FileNotFound)
- {
- if (shouldThrowWhenKeyMissing)
- throw new ArgumentException ("value " + value);
- RegTrace (" -DeleteValue");
- return;
- }
-
- if (result != Win32ResultCode.Success)
- {
- RegTrace ("Win32Api::RegDeleteValue: result='{0}' value name='{1}'",
- result, CombineName (value));
- GenerateException (result);
- }
-
- RegTrace (" -DeleteValue");
+
+ RegistryApi.DeleteValue (this, value, shouldThrowWhenKeyMissing);
}
/// </summary>
public string[] GetSubKeyNames()
{
- RegTrace (" +GetSubKeyNames");
AssertKeyStillValid ();
-
- byte[] buffer = new byte [BufferMaxLength];
- int bufferCapacity = BufferMaxLength;
- ArrayList keys = new ArrayList ();
-
- for (int index = 0; true; index ++)
- {
- int result = RegistryApi.RegEnumKey (Handle, index, buffer, bufferCapacity);
-
- if (result == Win32ResultCode.Success)
- {
- keys.Add (DecodeString (buffer));
- continue;
- }
-
- if (result == Win32ResultCode.NoMoreEntries)
- break;
-
- // should not be here!
- RegTrace ("Win32Api::RegEnumKey: result='{0}' value name='{1}'",
- result, CombineName (Name));
- GenerateException (result);
- }
- RegTrace (" -GetSubKeyNames");
- return (string []) keys.ToArray (typeof(String));
+ return RegistryApi.GetSubKeyNames (this);
}
/// </summary>
public string[] GetValueNames()
{
- RegTrace (" +GetValueNames");
AssertKeyStillValid ();
-
- ArrayList values = new ArrayList ();
-
- for (int index = 0; true; index ++)
- {
- StringBuilder buffer = new StringBuilder (BufferMaxLength);
- int bufferCapacity = buffer.Capacity;
- int type = 0;
-
- int result = RegistryApi.RegEnumValue (Handle, index, buffer, ref bufferCapacity,
- IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
-
- if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
- {
- values.Add (buffer.ToString ());
- continue;
- }
-
- if (result == Win32ResultCode.NoMoreEntries)
- break;
-
- // should not be here!
- RegTrace ("RegistryApi.RegEnumValue: result code='{0}' name='{1}'",
- result, CombineName (Name));
- GenerateException (result);
- }
-
- RegTrace (" -GetValueNames");
- return (string []) values.ToArray (typeof(String));
+ return RegistryApi.GetValueNames (this);
}
/// </summary>
public override string ToString()
{
- return String.Format ("{0} [0x{1:X}]", Name, Handle.ToInt32 ());
+ return RegistryApi.ToString (this);
}
#endregion // PublicAPI
/// </summary>
private void AssertKeyStillValid ()
{
- if (Handle == IntPtr.Zero)
+ if (Data == null)
throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
}
/// </summary>
private void DeleteChildKeysAndValues ()
{
- RegTrace (" +DeleteChildKeysAndValues");
if (isRoot)
- {
- RegTrace (" -DeleteChildKeysAndValues");
return;
- }
string[] subKeys = GetSubKeyNames ();
foreach (string subKey in subKeys)
}
string[] values = GetValueNames ();
- foreach (string value in values)
- {
+ foreach (string value in values) {
DeleteValue (value, false);
}
-
- RegTrace (" -DeleteChildKeysAndValues");
}
-
- /// <summary>
- /// Acctually read a registry value. Requires knoledge of the
- /// value's type and size.
- /// </summary>
- private object GetValueImpl (string name, bool returnDefaultValue, object defaultValue)
- {
- RegTrace (" +GetValueImpl");
- AssertKeyStillValid ();
-
- int type = 0;
- int size = 0;
- object obj = null;
-
- int result = RegistryApi.RegQueryValueEx (Handle, name, IntPtr.Zero,
- ref type, IntPtr.Zero, ref size);
-
- if (result == Win32ResultCode.FileNotFound)
- {
- if (returnDefaultValue) {
- RegTrace (" -GetValueImpl");
- return defaultValue;
- }
- return null;
- }
-
- if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success )
- {
- RegTrace ("Win32Api::RegQueryValueEx: result='{0}' name='{1}' type='{2}' size='{3}'",
- result, name, type, size);
- GenerateException (result);
- }
-
- if (type == RegistryApi.RegStringType || type == RegistryApi.RegEnvironmentString)
- {
- byte[] data;
- result = GetBinaryValue (name, type, out data, size);
- obj = DecodeString (data);
- }
- else if (type == RegistryApi.RegDwordType)
- {
- int data = 0;
- result = RegistryApi.RegQueryValueEx (Handle, name, IntPtr.Zero,
- ref type, ref data, ref size);
- obj = data;
- }
- else if (type == RegistryApi.RegBinaryType)
- {
- byte[] data;
- result = GetBinaryValue (name, type, out data, size);
- obj = data;
- }
- else if (type == RegistryApi.RegStringArrayType)
- {
- obj = null;
- byte[] data;
- result = GetBinaryValue (name, type, out data, size);
-
- if (result == Win32ResultCode.Success)
- obj = DecodeString (data).Split (NullChar);
- }
- else
- {
- // should never get here
- throw new SystemException ();
- }
-
- // check result codes again:
- if (result != Win32ResultCode.Success)
- {
- RegTrace ("Win32Api::RegQueryValueEx: result='{0}' name='{1}'",
- result, name);
- GenerateException (result);
- }
-
- RegTrace (" -ReadValueImpl");
- return obj;
- }
-
-
- /// <summary>
- /// Get a binary value.
- /// </summary>
- private int GetBinaryValue (string name, int type, out byte[] data, int size)
- {
- byte[] internalData = new byte [size];
- int result = RegistryApi.RegQueryValueEx (Handle, name,
- IntPtr.Zero, ref type, internalData, ref size);
- data = internalData;
- return result;
- }
-
-
/// <summary>
/// decode a byte array as a string, and strip trailing nulls
/// </summary>
- private string DecodeString (byte[] data)
+ static internal string DecodeString (byte[] data)
{
- string stringRep = Decoder.GetString (data);
- int idx = stringRep.IndexOf (NullChar);
+ string stringRep = Encoding.Unicode.GetString (data);
+ int idx = stringRep.IndexOf ('\0');
if (idx >= 0)
- stringRep = stringRep.Substring (0, idx);
+ stringRep = stringRep.Substring (0, idx);
return stringRep;
}
-
-
- /// <summary>
- /// utility: Combine the sub key name to the current name to produce a
- /// fully qualified sub key name.
- /// </summary>
- private string CombineName (string localName)
- {
- return String.Format ("{0}\\{1}", Name, localName);
- }
-
-
- /// <summary>
- /// convert a win32 error code into an appropriate exception.
- /// </summary>
- private void GenerateException (int errorCode)
- {
- switch (errorCode) {
- case Win32ResultCode.FileNotFound:
- case Win32ResultCode.InvalidParameter:
- throw new ArgumentException ();
-
- case Win32ResultCode.AccessDenied:
- throw new SecurityException ();
-
- default:
- // unidentified system exception
- throw new SystemException ();
- }
- }
-
-#if (false)
- /// <summary>
- /// dump trace messages if this code was compiled with tracing enabled.
- /// </summary>
- [Conditional("TRACE")]
- private static void RegTrace (string message, params object[] args)
- {
- message = "REG " + message;
- if (args.Length > 0)
- message = String.Format (message, args);
-
- Trace.WriteLine (message);
- //Console.WriteLine (message);
- }
-#endif
- private static void RegTrace (string message, params object[] args)
- {
- }
}
}
--- /dev/null
+//
+// Microsoft.Win32/IRegistryApi.cs
+//
+// Authors:
+// Miguel de Icaza (miguel@gnome.org)
+//
+// (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// MISSING:
+// Someone could the same subkey twice: once read/write once readonly,
+// currently since we use a unique hash based on the file name, we are unable
+// to have two versions of the same key and hence unable to throw an exception
+// if the user tries to write to a read-only key.
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Security;
+using System.Threading;
+
+namespace Microsoft.Win32 {
+
+ class KeyHandler {
+ static Hashtable key_to_handler = new Hashtable ();
+ static Hashtable dir_to_key = new Hashtable ();
+ public string Dir;
+ public IntPtr Handle;
+
+ public Hashtable values;
+ string file;
+ bool dirty;
+
+ KeyHandler (RegistryKey rkey, string basedir)
+ {
+ if (!Directory.Exists (basedir)){
+ try {
+ Directory.CreateDirectory (basedir);
+ } catch (Exception e){
+ Console.Error.WriteLine ("KeyHandler error while creating directory {0}:\n{1}", basedir, e);
+ }
+ }
+ Dir = basedir;
+ file = Path.Combine (Dir, "values.xml");
+ Load ();
+ }
+
+ public void Load ()
+ {
+ values = new Hashtable ();
+ if (!File.Exists (file))
+ return;
+
+ try {
+ using (FileStream fs = File.OpenRead (file)){
+ StreamReader r = new StreamReader (fs);
+ string xml = r.ReadToEnd ();
+ if (xml.Length == 0)
+ return;
+
+ SecurityElement tree = SecurityElement.FromString (xml);
+ if (tree.Tag == "values"){
+ foreach (SecurityElement value in tree.Children){
+ if (value.Tag == "value"){
+ LoadKey (value);
+ }
+ }
+ }
+ }
+ } catch (Exception e){
+ Console.Error.WriteLine ("While loading registry key at {0}: {1}", file, e);
+ values.Clear ();
+ }
+ }
+
+ void LoadKey (SecurityElement se)
+ {
+ Hashtable h = se.Attributes;
+ try {
+ string name = (string) h ["name"];
+ if (name == null)
+ return;
+ string type = (string) h ["type"];
+ if (type == null)
+ return;
+
+ switch (type){
+ case "int":
+ values [name] = Int32.Parse (se.Text);
+ break;
+ case "bytearray":
+ Convert.FromBase64String (se.Text);
+ break;
+ case "string":
+ values [name] = se.Text;
+ break;
+ case "string-array":
+ ArrayList sa = new ArrayList ();
+ if (se.Children != null){
+ foreach (SecurityElement stre in se.Children){
+ sa.Add (stre.Text);
+ }
+ }
+ values [name] = sa.ToArray (typeof (string));
+ break;
+ }
+ } catch {
+ // We ignore individual errors in the file.
+ }
+ }
+
+ public RegistryKey Ensure (RegistryKey rkey, string extra)
+ {
+ lock (typeof (KeyHandler)){
+ string f = Path.Combine (Dir, extra);
+ if (dir_to_key.Contains (f))
+ return (RegistryKey) dir_to_key [f];
+
+ KeyHandler kh = new KeyHandler (rkey, f);
+ RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
+ key_to_handler [rk] = kh;
+ dir_to_key [f] = rk;
+ return rk;
+ }
+ }
+
+ public RegistryKey Probe (RegistryKey rkey, string extra, bool write)
+ {
+ lock (typeof (KeyHandler)){
+ string f = Path.Combine (Dir, extra);
+ if (dir_to_key.Contains (f))
+ return (RegistryKey) dir_to_key [f];
+ Console.WriteLine ("Trying: " + f);
+ if (Directory.Exists (f)){
+ KeyHandler kh = new KeyHandler (rkey, f);
+ RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
+ dir_to_key [f] = rk;
+ key_to_handler [rk] = kh;
+ return rk;
+ }
+ return null;
+ }
+ }
+
+ static string CombineName (RegistryKey rkey, string extra)
+ {
+ if (extra.IndexOf ('/') != -1)
+ extra = extra.Replace ('/', '\\');
+
+ return String.Concat (rkey.Name, "\\", extra);
+ }
+
+ public static KeyHandler Lookup (RegistryKey rkey)
+ {
+ lock (typeof (KeyHandler)){
+ KeyHandler k = (KeyHandler) key_to_handler [rkey];
+ if (k != null)
+ return k;
+
+ RegistryHive x = (RegistryHive) rkey.Data;
+ switch (x){
+ case RegistryHive.ClassesRoot:
+ case RegistryHive.CurrentConfig:
+ case RegistryHive.CurrentUser:
+ case RegistryHive.DynData:
+ case RegistryHive.LocalMachine:
+ case RegistryHive.PerformanceData:
+ case RegistryHive.Users:
+ string d = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".mono/registry");
+ d = Path.Combine (d, x.ToString ());
+
+ k = new KeyHandler (rkey, d);
+ key_to_handler [rkey] = k;
+ break;
+ default:
+ throw new Exception ("Unknown RegistryHive");
+ }
+ key_to_handler [rkey] = k;
+ return k;
+ }
+ }
+
+ public static void Drop (RegistryKey rkey)
+ {
+ KeyHandler k = (KeyHandler) key_to_handler [rkey];
+ if (k == null)
+ return;
+ dir_to_key.Remove (k.Dir);
+ key_to_handler.Remove (rkey);
+ }
+
+ public static void Drop (string dir)
+ {
+ if (dir_to_key.Contains (dir)){
+ key_to_handler.Remove (dir_to_key [dir]);
+ dir_to_key.Remove (dir);
+ }
+ }
+
+ public void SetValue (string name, object value)
+ {
+ values [name] = value;
+ SetDirty ();
+ }
+
+ void SetDirty ()
+ {
+ lock (typeof (KeyHandler)){
+ if (dirty)
+ return;
+ dirty = true;
+ new Timer (DirtyTimeout, null, 3000, Timeout.Infinite);
+ }
+ }
+
+ public void DirtyTimeout (object state)
+ {
+ Flush ();
+ }
+
+ public void Flush ()
+ {
+ lock (typeof (KeyHandler)){
+ dirty = false;
+ Save ();
+ }
+ }
+
+ ~KeyHandler ()
+ {
+ Flush ();
+ }
+
+ void Save ()
+ {
+ if (!File.Exists (file) && values.Count == 0)
+ return;
+
+ SecurityElement se = new SecurityElement ("values");
+
+ foreach (DictionaryEntry de in values){
+ object val = de.Value;
+ SecurityElement value = new SecurityElement ("value");
+ value.AddAttribute ("name", (string) de.Key);
+
+ if (val is string){
+ value.AddAttribute ("type", "string");
+ value.Text = (string) val;
+ } else if (val is int){
+ value.AddAttribute ("type", "int");
+ value.Text = val.ToString ();
+ } else if (val is byte []){
+ value.AddAttribute ("type", "bytearray");
+ value.Text = Convert.ToBase64String ((byte[]) val);
+ } else if (val is string []){
+ value.AddAttribute ("type", "string-array");
+
+ foreach (string ss in (string[]) val){
+ SecurityElement str = new SecurityElement ("string");
+ str.Text = ss;
+ value.AddChild (str);
+ }
+ }
+ se.AddChild (value);
+ }
+
+ try {
+ using (FileStream fs = File.Create (file)){
+ StreamWriter sw = new StreamWriter (fs);
+
+ sw.Write (se.ToString ());
+ sw.Flush ();
+ }
+ } catch (Exception e){
+ Console.Error.WriteLine ("When saving {0} got {1}", file, e);
+ }
+ }
+ }
+
+ internal class UnixRegistryApi : IRegistryApi {
+
+ static string ToUnix (string keyname)
+ {
+ if (keyname.IndexOf ('\\') != -1)
+ keyname = keyname.Replace ('\\', '/');
+ return keyname.ToLower ();
+ }
+
+ public RegistryKey CreateSubKey (RegistryKey rkey, string keyname)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ return self.Ensure (rkey, ToUnix (keyname));
+ }
+
+ public RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writtable)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ return self.Probe (rkey, ToUnix (keyname), writtable);
+ }
+
+ public void Flush (RegistryKey rkey)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ self.Flush ();
+ }
+
+ public void Close (RegistryKey rkey)
+ {
+ KeyHandler.Drop (rkey);
+ }
+
+ public object GetValue (RegistryKey rkey, string name, bool return_default_value, object default_value)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+
+ if (self.values.Contains (name))
+ return self.values [name];
+ if (return_default_value)
+ return default_value;
+ return null;
+ }
+
+ public void SetValue (RegistryKey rkey, string name, object value)
+ {
+ if (!((value is int) || (value is string) || (value is string []) || (value is byte [])))
+ throw new ArgumentException ("The value is not int, string, string[] or byte[]", "value");
+
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ self.SetValue (name, value);
+ }
+
+ public int SubKeyCount (RegistryKey rkey)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+
+ return Directory.GetDirectories (self.Dir).Length;
+ }
+
+ public int ValueCount (RegistryKey rkey)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+
+ return self.values.Keys.Count;
+ }
+
+ public void DeleteValue (RegistryKey rkey, string value, bool throw_if_missing)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+
+ foreach (DictionaryEntry de in self.values){
+ if ((string)de.Value == value){
+ self.values.Remove (de.Key);
+ return;
+ }
+ }
+ if (throw_if_missing)
+ throw new ArgumentException ("the given value does not exist", "value");
+ }
+
+ public void DeleteKey (RegistryKey rkey, string keyname, bool throw_if_missing)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ string dir = Path.Combine (self.Dir, keyname);
+
+ if (Directory.Exists (dir)){
+ Directory.Delete (dir, true);
+ KeyHandler.Drop (dir);
+ } else if (throw_if_missing)
+ throw new ArgumentException ("the given value does not exist", "value");
+ }
+
+ public string [] GetSubKeyNames (RegistryKey rkey)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ return Directory.GetDirectories (self.Dir);
+ }
+
+ public string [] GetValueNames (RegistryKey rkey)
+ {
+ KeyHandler self = KeyHandler.Lookup (rkey);
+ ICollection keys = self.values.Keys;
+
+ string [] vals = new string [keys.Count];
+ keys.CopyTo (vals, 0);
+ return vals;
+ }
+
+ public string ToString (RegistryKey rkey)
+ {
+ return rkey.Name;
+ }
+ }
+}
// Authos:
// Erik LeBel (eriklebel@yahoo.ca)
// Jackson Harper (jackson@ximian.com)
+// Miguel de Icaza (miguel@gnome.org)
//
// Copyright (C) Erik LeBel 2004
-// (C) 2004 Novell, Inc (http://www.novell.com)
+// (C) 2004, 2005 Novell, Inc (http://www.novell.com)
//
//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
//
using System;
+using System.Collections;
using System.Runtime.InteropServices;
+using System.Security;
using System.Text;
namespace Microsoft.Win32
internal class Win32RegistryApi : IRegistryApi
{
// bit masks for registry key open access permissions
- public int OpenRegKeyRead {
- get { return 0x00020019; }
- }
+ const int OpenRegKeyRead = 0x00020019;
+ const int OpenRegKeyWrite = 0x00020006;
+
+ // FIXME must be a way to determin this dynamically?
+ const int Int32ByteSize = 4;
- public int OpenRegKeyWrite {
- get { return 0x00020006; }
+ // FIXME this is hard coded on Mono, can it be determined dynamically?
+ readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
+
+ internal enum RegistryType {
+ String = 1,
+ EnvironmentString = 2,
+ Binary = 3,
+ Dword = 4,
+ StringArray = 7,
}
- // type values for registry value data
- public int RegStringType {
- get { return 1; }
- }
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKey")]
+ static extern int RegCreateKey (IntPtr keyBase, string keyName, out IntPtr keyHandle);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
+ static extern int RegCloseKey (IntPtr keyHandle);
- public int RegEnvironmentString {
- get { return 2; }
- }
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
+ private static extern int RegFlushKey (IntPtr keyHandle);
- public int RegBinaryType {
- get { return 3; }
- }
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
+ private static extern int RegOpenKeyEx (IntPtr keyBase,
+ string keyName, IntPtr reserved, int access,
+ out IntPtr keyHandle);
- public int RegDwordType {
- get { return 4; }
- }
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
+ private static extern int RegDeleteKey (IntPtr keyHandle, string valueName);
- public int RegStringArrayType {
- get { return 7; }
- }
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
+ private static extern int RegDeleteValue (IntPtr keyHandle, string valueName);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
+ private static extern int RegEnumKey (IntPtr keyBase, int index, [Out] byte[] nameBuffer, int bufferLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
+ private static extern int RegEnumValue (IntPtr keyBase,
+ int index, StringBuilder nameBuffer,
+ ref int nameLength, IntPtr reserved,
+ ref RegistryType type, IntPtr data, IntPtr dataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+ private static extern int RegSetValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, RegistryType type,
+ StringBuilder data, int rawDataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+ private static extern int RegSetValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, RegistryType type,
+ string data, int rawDataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+ private static extern int RegSetValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, RegistryType type,
+ byte[] rawData, int rawDataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+ private static extern int RegSetValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, RegistryType type,
+ ref int data, int rawDataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
+ private static extern int RegQueryValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, ref RegistryType type,
+ IntPtr zero, ref int dataSize);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
+ private static extern int RegQueryValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, ref RegistryType type,
+ [Out] byte[] data, ref int dataSize);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
+ private static extern int RegQueryValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, ref RegistryType type,
+ ref int data, ref int dataSize);
/// <summary>
- /// Create a registry key.
+ /// Acctually read a registry value. Requires knoledge of the
+ /// value's type and size.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKey")]
- private static extern int RegCreateKey_Internal (IntPtr keyBase,
- string keyName, out IntPtr keyHandle);
-
- public int RegCreateKey (IntPtr keybase, string keyname, out IntPtr handle)
+ public object GetValue (RegistryKey rkey, string name, bool returnDefaultValue, object defaultValue)
{
- return RegCreateKey_Internal (keybase, keyname, out handle);
+ RegistryType type = 0;
+ int size = 0;
+ object obj = null;
+ IntPtr handle = (IntPtr)rkey.Data;
+ int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
+
+ if (result == Win32ResultCode.FileNotFound) {
+ if (returnDefaultValue) {
+ return defaultValue;
+ }
+ return null;
+ }
+
+ if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success ) {
+ GenerateException (result);
+ }
+
+ if (type == RegistryType.String || type == RegistryType.EnvironmentString) {
+ byte[] data;
+ result = GetBinaryValue (rkey, name, type, out data, size);
+ obj = RegistryKey.DecodeString (data);
+ } else if (type == RegistryType.Dword) {
+ int data = 0;
+ result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
+ obj = data;
+ } else if (type == RegistryType.Binary) {
+ byte[] data;
+ result = GetBinaryValue (rkey, name, type, out data, size);
+ obj = data;
+ } else if (type == RegistryType.StringArray) {
+ obj = null;
+ byte[] data;
+ result = GetBinaryValue (rkey, name, type, out data, size);
+
+ if (result == Win32ResultCode.Success)
+ obj = RegistryKey.DecodeString (data).Split ('\0');
+ } else {
+ // should never get here
+ throw new SystemException ();
+ }
+
+ // check result codes again:
+ if (result != Win32ResultCode.Success)
+ {
+ GenerateException (result);
+ }
+
+
+ return obj;
}
-
- /// <summary>
- /// Close a registry key.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
- private static extern int RegCloseKey_Internal (IntPtr keyHandle);
- public int RegCloseKey (IntPtr handle)
+ public void SetValue (RegistryKey rkey, string name, object value)
{
- return RegCloseKey_Internal (handle);
+ Type type = value.GetType ();
+ int result;
+ IntPtr handle = (IntPtr)rkey.Data;
+
+ if (type == typeof (int)) {
+ int rawValue = (int)value;
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.Dword, ref rawValue, Int32ByteSize);
+ } else if (type == typeof (byte[])) {
+ byte[] rawValue = (byte[]) value;
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.Binary, rawValue, rawValue.Length);
+ } else if (type == typeof (string[])) {
+ string[] vals = (string[]) value;
+ StringBuilder fullStringValue = new StringBuilder ();
+ foreach (string v in vals)
+ {
+ fullStringValue.Append (v);
+ fullStringValue.Append ('\0');
+ }
+ fullStringValue.Append ('\0');
+
+ byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
+
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.StringArray, rawValue, rawValue.Length);
+ } else if (type.IsArray) {
+ throw new ArgumentException ("Only string and byte arrays can written as registry values");
+ } else {
+ string rawValue = String.Format ("{0}{1}", value, '\0');
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.String, rawValue,
+ rawValue.Length * NativeBytesPerCharacter);
+ }
+
+ // handle the result codes
+ if (result != Win32ResultCode.Success)
+ {
+ GenerateException (result);
+ }
}
/// <summary>
- /// Flush a registry key's current state to disk.
+ /// Get a binary value.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
- private static extern int RegFlushKey_Internal (IntPtr keyHandle);
-
- public int RegFlushKey (IntPtr handle)
+ private int GetBinaryValue (RegistryKey rkey, string name, RegistryType type, out byte[] data, int size)
{
- return RegFlushKey_Internal (handle);
+ byte[] internalData = new byte [size];
+ IntPtr handle = (IntPtr)rkey.Data;
+ int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
+ data = internalData;
+ return result;
}
- /// <summary>
- /// Open a registry key.
- /// 'unknown' must be zero.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
- private static extern int RegOpenKeyEx_Internal (IntPtr keyBase,
- string keyName, IntPtr reserved, int access,
- out IntPtr keyHandle);
-
- public int RegOpenKeyEx (IntPtr keybase, string keyname, IntPtr reserved,
- int access, out IntPtr handle)
+
+ // Arbitrary max size for key/values names that can be fetched.
+ // .NET framework SDK docs say that the max name length that can
+ // be used is 255 characters, we'll allow for a bit more.
+ const int BufferMaxLength = 1024;
+
+ public int SubKeyCount (RegistryKey rkey)
{
- return RegOpenKeyEx_Internal (keybase, keyname, reserved, access, out handle);
+ int index, result;
+ byte[] stringBuffer = new byte [BufferMaxLength];
+ IntPtr handle = (IntPtr)rkey.Data;
+
+ for (index = 0; true; index ++) {
+ result = RegEnumKey (handle, index, stringBuffer, BufferMaxLength);
+
+ if (result == Win32ResultCode.Success)
+ continue;
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ // something is wrong!!
+ GenerateException (result);
+ }
+ return index;
}
- /// <summary>
- /// Delete a registry key.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
- private static extern int RegDeleteKey_Internal (IntPtr keyHandle,
- string valueName);
-
- public int RegDeleteKey (IntPtr handle, string valuename)
+ public int ValueCount (RegistryKey rkey)
{
- return RegDeleteKey_Internal (handle, valuename);
+ int index, result, bufferCapacity;
+ RegistryType type;
+ StringBuilder buffer = new StringBuilder (BufferMaxLength);
+
+ IntPtr handle = (IntPtr)rkey.Data;
+ for (index = 0; true; index ++) {
+ type = 0;
+ bufferCapacity = buffer.Capacity;
+ result = RegEnumValue (handle, index,
+ buffer, ref bufferCapacity,
+ IntPtr.Zero, ref type,
+ IntPtr.Zero, IntPtr.Zero);
+
+ if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
+ continue;
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ // something is wrong
+ GenerateException (result);
+ }
+ return index;
}
-
- /// <summary>
- /// Delete a registry value.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
- private static extern int RegDeleteValue_Internal (IntPtr keyHandle,
- string valueName);
-
- public int RegDeleteValue (IntPtr handle, string valuename)
+
+ public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writtable)
{
- return RegDeleteValue_Internal (handle, valuename);
+ int access = OpenRegKeyRead;
+ if (writtable) access |= OpenRegKeyWrite;
+ IntPtr handle = (IntPtr)rkey.Data;
+
+ IntPtr subKeyHandle;
+ int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
+
+ if (result == Win32ResultCode.FileNotFound)
+ return null;
+
+ if (result != Win32ResultCode.Success)
+ GenerateException (result);
+
+ return new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
}
- /// <summary>
- /// Fetch registry key subkeys itteratively.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
- private static extern int RegEnumKey_Internal (IntPtr keyBase, int index,
- [Out] byte[] nameBuffer, int bufferLength);
-
- public int RegEnumKey (IntPtr keybase, int index,
- [Out] byte [] namebuffer, int buffer_length)
+ public void Flush (RegistryKey rkey)
{
- return RegEnumKey_Internal (keybase, index, namebuffer, buffer_length);
+ IntPtr handle = (IntPtr)rkey.Data;
+ RegFlushKey (handle);
}
- /// <summary>
- /// Fetch registry key value names itteratively.
- ///
- /// Arguments 'reserved', 'data', 'dataLength'
- /// should be set to IntPtr.Zero.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
- private static extern int RegEnumValue_Internal (IntPtr keyBase,
- int index, StringBuilder nameBuffer,
- ref int nameLength, IntPtr reserved,
- ref int type, IntPtr data, IntPtr dataLength);
-
- public int RegEnumValue (IntPtr keybase, int index, StringBuilder namebuffer,
- ref int namelength, IntPtr reserved, ref int type, IntPtr data,
- IntPtr datalength)
+ public void Close (RegistryKey rkey)
{
- return RegEnumValue_Internal (keybase, index, namebuffer, ref namelength,
- reserved, ref type, data, datalength);
+ IntPtr handle = (IntPtr)rkey.Data;
+ RegCloseKey (handle);
}
- /// <summary>
- /// Set a registry value with string builder data.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- StringBuilder data, int rawDataLength);
-
- public int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, StringBuilder data, int datalength)
+ public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved,
- type, data, datalength);
- }
+ IntPtr handle = (IntPtr)rkey.Data;
+ IntPtr subKeyHandle;
+ int result = RegCreateKey (handle , keyName, out subKeyHandle);
- /// <summary>
- /// Set a registry value with string data.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- string data, int rawDataLength);
+ if (result != Win32ResultCode.Success) {
+ GenerateException (result);
+ }
+
+ RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
+
+ return subKey;
+ }
- public int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, string data, int datalength)
+ public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved,
- type, data, datalength);
+ IntPtr handle = (IntPtr)rkey.Data;
+ int result = RegDeleteKey (handle, keyName);
+
+ if (result == Win32ResultCode.FileNotFound) {
+ if (shouldThrowWhenKeyMissing)
+ throw new ArgumentException ("key " + keyName);
+ return;
+ }
+
+ if (result != Win32ResultCode.Success)
+ GenerateException (result);
}
-
- /// <summary>
- /// Set a registry value with binary data (a byte array).
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- byte[] rawData, int rawDataLength);
- public int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, byte [] data, int datalength)
+ public void DeleteValue (RegistryKey rkey, string value, bool shouldThrowWhenKeyMissing)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved,
- type, data, datalength);
+ IntPtr handle = (IntPtr)rkey.Data;
+ int result = RegDeleteValue (handle, value);
+
+ if (result == Win32ResultCode.FileNotFound){
+ if (shouldThrowWhenKeyMissing)
+ throw new ArgumentException ("value " + value);
+ return;
+ }
+
+ if (result != Win32ResultCode.Success)
+ GenerateException (result);
}
-
- /// <summary>
- /// Set a registry value to a DWORD value.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- ref int data, int rawDataLength);
- public int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, ref int data, int datalength)
+ public string [] GetSubKeyNames (RegistryKey rkey)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved, type,
- ref data, datalength);
+ IntPtr handle = (IntPtr)rkey.Data;
+ byte[] buffer = new byte [BufferMaxLength];
+ int bufferCapacity = BufferMaxLength;
+ ArrayList keys = new ArrayList ();
+
+ for (int index = 0; true; index ++) {
+ int result = RegEnumKey (handle, index, buffer, bufferCapacity);
+
+ if (result == Win32ResultCode.Success) {
+ keys.Add (RegistryKey.DecodeString (buffer));
+ continue;
+ }
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ // should not be here!
+ GenerateException (result);
+ }
+ return (string []) keys.ToArray (typeof(String));
}
- /// <summary>
- /// Get a registry value's info. No data.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
- private static extern int RegQueryValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- IntPtr zero, ref int dataSize);
- public int RegQueryValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- ref int type, IntPtr zero, ref int datasize)
+ public string [] GetValueNames (RegistryKey rkey)
{
- return RegQueryValueEx_Internal (keybase, valuename, reserved,
- ref type, zero, ref datasize);
+ IntPtr handle = (IntPtr)rkey.Data;
+ ArrayList values = new ArrayList ();
+
+ for (int index = 0; true; index ++)
+ {
+ StringBuilder buffer = new StringBuilder (BufferMaxLength);
+ int bufferCapacity = buffer.Capacity;
+ RegistryType type = 0;
+
+ int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
+ IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
+
+ if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData) {
+ values.Add (buffer.ToString ());
+ continue;
+ }
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ GenerateException (result);
+ }
+
+ return (string []) values.ToArray (typeof(String));
}
/// <summary>
- /// Get a registry value. Binary data.
+ /// convert a win32 error code into an appropriate exception.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
- private static extern int RegQueryValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- [Out] byte[] data, ref int dataSize);
+ private void GenerateException (int errorCode)
+ {
+ switch (errorCode) {
+ case Win32ResultCode.FileNotFound:
+ case Win32ResultCode.InvalidParameter:
+ throw new ArgumentException ();
+
+ case Win32ResultCode.AccessDenied:
+ throw new SecurityException ();
+
+ default:
+ // unidentified system exception
+ throw new SystemException ();
+ }
+ }
- public int RegQueryValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- ref int type, [Out] byte [] data, ref int datasize)
+ public string ToString (RegistryKey rkey)
{
- return RegQueryValueEx_Internal (keybase, valuename, reserved,
- ref type, data, ref datasize);
+ IntPtr handle = (IntPtr)rkey.Data;
+
+ return String.Format ("{0} [0x{1:X}]", rkey.Name, handle.ToInt32 ());
}
/// <summary>
- /// Get a registry value. DWORD data.
+ /// utility: Combine the sub key name to the current name to produce a
+ /// fully qualified sub key name.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
- private static extern int RegQueryValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- ref int data, ref int dataSize);
-
- public int RegQueryValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- ref int type, ref int data, ref int datasize)
+ internal static string CombineName (RegistryKey rkey, string localName)
{
- return RegQueryValueEx_Internal (keybase, valuename, reserved,
- ref type, ref data, ref datasize);
+ return String.Concat (rkey.Name, "\\", localName);
}
}
}
Microsoft.Win32/RegistryKey.cs
Microsoft.Win32/Registry.cs
Microsoft.Win32/RegistryHive.cs
+Microsoft.Win32/UnixRegistryApi.cs
Microsoft.Win32/Win32RegistryApi.cs
Microsoft.Win32/Win32ResultCode.cs
Microsoft.Win32.SafeHandles/SafeHandleZeroOrMinusOneIsInvalid.cs