using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Microsoft.Win32;
/*******************************************************************************************
* Author: Tim Almdal
* Date: Sept, 2006
* tnalmdal (at) shaw-dot-net
*
* RegistryScript class. Parses and processes a ATL like registry
* Script for update application settings in the registry
*
* Copyright (c) 2006 T. ALmdal
*
* 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.
*
/*******************************************************************************************/
namespace Almdal.RegistryScript {
/// <summary>
/// Enum of the available Registry Operations on the process key
/// </summary>
internal enum RegistryOperation {
OpenKey,
DeleteKey,
CloseKey,
DeleteAddKey,
AddKey,
AddValue,
DeleteValue,
}
#region Processing Queue Item Definition
/// <summary>
/// Class that represents an entry on the Registy Process Queue
/// </summary>
internal class RegistryOpQueueItem {
public RegistryOperation _op;
public string _key;
public string _value;
public RegistryValueKind _type;
/// <summary>
/// Create Registry Process Key Entry with no key name.
/// </summary>
/// <param name="op">The Registry Operation to Perform</param>
public RegistryOpQueueItem(RegistryOperation op) {
_op = op;
_key = "";
_value = "";
_type = RegistryValueKind.Unknown;
}
/// <summary>
///
/// </summary>
/// <param name="op">The Registry Operation to Perform</param>
/// <param name="key">The name of the key or value to operate on</param>
public RegistryOpQueueItem(RegistryOperation op, string key)
: this(op) {
_key = key;
}
/// <summary>
/// Override for pretty output when debuggin
/// </summary>
/// <returns>A String representation</returns>
public override string ToString() {
StringBuilder sb = new StringBuilder(128);
sb.Append(base.ToString()).Append('[');
sb.Append("Op: ").Append(_op);
sb.Append("; Key: ").Append(_key);
sb.Append("; Value: ").Append(_value);
sb.Append("; ValueType: ").Append(_type);
sb.Append(']');
return sb.ToString();
}
}
#endregion
#region Registry Key Stack Item
/// <summary>
/// Class the represents a registry key on a stack, When a key is
/// added or opened, it goes on the stack so that we have access to
/// the current parent key. If the key was deleted, then an entry
/// goes on the stack, but there is no RegistryKey class associated
/// with it.
/// </summary>
internal class ReqistryOpStackItem {
public string _keyName;
public bool _isDeleted;
public RegistryKey _key = null;
public ReqistryOpStackItem(string keyName) : this(keyName, null) { }
public ReqistryOpStackItem(string keyName, RegistryKey key) {
_keyName = keyName;
_key = key;
_isDeleted = key == null;
}
}
#endregion
/// <summary>
/// The Registry operations process queue class.
/// </summary>
internal class OpQueue : Queue<RegistryOpQueueItem> {
/// <summary>
/// Stack of registry keys
/// </summary>
Stack<ReqistryOpStackItem> _keyStack = new Stack<ReqistryOpStackItem>();
/// <summary>
/// Public method to process the entries in the process queue.
/// </summary>
public void ProcessRegistryQueue() {
for (RegistryOpQueueItem qi = this.Dequeue();
this.Count != 0;
qi = this.Dequeue()) {
switch (qi._op) {
case RegistryOperation.OpenKey:
OpenKey(qi);
break;
case RegistryOperation.DeleteAddKey:
DeleteAddKey(qi);
break;
case RegistryOperation.DeleteKey:
DeleteKey(qi);
break;
case RegistryOperation.CloseKey:
CloseKey(qi);
break;
case RegistryOperation.AddKey:
AddKey(qi);
break;
case RegistryOperation.AddValue:
AddValue(qi);
break;
case RegistryOperation.DeleteValue:
DeleteValue(qi);
break;
}
}
}
/// <summary>
/// Open the specified key.
///
/// If there is nothing on then stack then open
/// a registry root key. Life is simplified as we smartly used the
/// Registry.fieldName as the key name. This allows us to retireve
/// the Registry Key by reflection.
///
/// Otherwise, open the key as a sub key of the top of the registry
/// key stack. Before attempting to open the subkey, verify that the
/// parent is not deleted.
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void OpenKey(RegistryOpQueueItem qi) {
RegistryKey regKey;
if (_keyStack.Count == 0) {
FieldInfo field = typeof(Registry).GetField(qi._key, BindingFlags.Static |
BindingFlags.Public);
regKey = (RegistryKey)field.GetValue(null);
}
else {
if (!_keyStack.Peek()._isDeleted) { // the parent is not deleted then delete it
regKey = _keyStack.Peek()._key.OpenSubKey(qi._key, true);
}
else {
regKey = null;
}
}
_keyStack.Push(new ReqistryOpStackItem(qi._key, regKey));
}
/// <summary>
/// Delete the specified key and all of its childern, then readd the key
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void DeleteAddKey(RegistryOpQueueItem qi) {
RegistryKey regKey = _keyStack.Peek()._key;
try {
regKey.DeleteSubKeyTree(qi._key);
} catch (ArgumentException ) {
}
AddKey(qi);
}
/// <summary>
/// Delete the specified key and all its children from the registry
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void DeleteKey(RegistryOpQueueItem qi) {
if (!_keyStack.Peek()._isDeleted) { // the parent is not deleted then delete it
RegistryKey regKey = _keyStack.Peek()._key;
try {
regKey.DeleteSubKeyTree(qi._key);
} catch (ArgumentException) {
}
}
_keyStack.Push(new ReqistryOpStackItem(qi._key));
}
/// <summary>
/// Close the key at the top of the Registry Key stack
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void CloseKey(RegistryOpQueueItem qi) {
ReqistryOpStackItem top = _keyStack.Pop();
if (!top._isDeleted) {
top._key.Close();
}
}
/// <summary>
/// Adds a key to registry. After it is added, the entry is added to the
/// top of the Registry Key stack.
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void AddKey(RegistryOpQueueItem qi) {
RegistryKey newKey = null;
if (!_keyStack.Peek()._isDeleted) { // the parent is not deleted then delete it
RegistryKey regKey = _keyStack.Peek()._key;
newKey = regKey.CreateSubKey(qi._key);
}
_keyStack.Push(new ReqistryOpStackItem(qi._key, newKey));
}
/// <summary>
/// Add specified value to the registry
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void AddValue(RegistryOpQueueItem qi) {
if (!_keyStack.Peek()._isDeleted) { // the parent is not deleted then delete it
RegistryKey regKey = _keyStack.Peek()._key;
switch (qi._type) {
case RegistryValueKind.String:
regKey.SetValue(string.Empty.Equals(qi._key) ? null : qi._key, qi._value, qi._type);
break;
case RegistryValueKind.Binary:
throw new NotImplementedException("Registry value type '" + qi._type + "' isnot implemented");
case RegistryValueKind.DWord:
int dword = Convert.ToInt32(qi._value);
regKey.SetValue(string.Empty.Equals(qi._key) ? null : qi._key, dword, qi._type);
break;
case RegistryValueKind.MultiString:
throw new NotImplementedException("Registry value type '" + qi._type + "' isnot implemented");
default:
throw new NotImplementedException("Registry value type '" + qi._type + "' isnot implemented");
}
}
}
/// <summary>
/// Delete the specified valuefrom the registry
/// </summary>
/// <param name="qi">The Registry Operations Queue entry</param>
private void DeleteValue(RegistryOpQueueItem qi) {
if (!_keyStack.Peek()._isDeleted) { // the parent is not deleted then delete it
RegistryKey regKey = _keyStack.Peek()._key;
regKey.DeleteValue(qi._key, false);
}
}
}
}