Files
AllPurposeAutoSetup/AllPurposeAutoSetup/WindowsRegistryManager.cs
2025-03-13 18:24:10 -07:00

605 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.IO;
using System.Security.AccessControl;
using System.Management;
using System.Security.Principal;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Drawing;
using CommonLib.Windows.Forms;
using CommonLib.IO;
using CommonLib.Misc;
using CommonLib.Windows.Misc;
namespace All_Purpose_Auto_Setup
{
class WindowsRegistryManager
{
// An event that can be raised, allowing other classes to
// subscribe to it and do what they like with the message.
public event Action<string, string, List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>> UpdateStatusDisplayAndLogEvent;
// this dictionary stores registry path and its associated properties
// it would look like this:
// [ reg1_path ] -> List[reg1_action,reg1_type, etc]
// [ reg2_path ] -> List[reg2_action,reg2_type, etc]
public Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> regPathToVariousThings = new Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>>();
Form m_parentForm;
public WindowsRegistryManager(Form parentForm)
{
m_parentForm = parentForm;
}
public bool ModifyWindowsRegistry(string sectionName)
{
bool setupSuccessful = true;
string msg;
string indentation = String.Empty;
CommonLib.Windows.Forms.TextFormat.TextFontAndColor defaultTextProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
CommonLib.Windows.Forms.TextFormat.TextFontAndColor textProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();
string registryPath, registryType, registryAction;
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStepTitleColor();
textProp.wordIndex = 0;
textProp.wordCount = 100;
textPropList.Add(textProp);
DateTime dat1 = DateTime.Now;
msg = "\n\n<-------------------Date and Time: " + dat1.ToString(@"MM/dd/yyyy hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture) + "------------------->";
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStepTitleColor();
textProp.wordIndex = 0;
textProp.wordCount = 100;
// set font size
textProp.textFont = new Font(textProp.textFont.Name, 12);
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList.Add(textProp);
msg = "\n-=Modifying Windows Registry=-";
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
regPathToVariousThings.Clear();
ConfigFileManager.readOneToManyDictionary(ConfigFileManager.ms_configGeneralInfo.iniFile,
sectionName, @"(reg\d+)_path$", @"(reg\d+)_.+", regPathToVariousThings);
setupSuccessful = verifyConfigInfo();
if (setupSuccessful)
{
if (regPathToVariousThings.Count == 0)
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList.Add(textProp);
indentation = Common.getIndentation(1);
msg = "\n" + indentation + "- SKIPPED. Nothing to set";
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
}
// for every app name to be installed/checked
foreach (KeyValuePair<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> entry in regPathToVariousThings)
{
registryPath = entry.Key.iniValue;
registryType = "";
registryAction = "";
Dictionary<string, string> registryNameValuePairs = new Dictionary<string, string>();
getRegistryInfo(entry.Value, ref registryAction, ref registryType, registryNameValuePairs);
registryAction = registryAction.Trim();
registryType = registryType.Trim();
setupSuccessful = modifyRegistryKey(registryPath, registryType, registryAction, registryNameValuePairs);
if (!setupSuccessful)
break;
}
}
return setupSuccessful;
}
public bool modifyRegistryKey(string registryPath, string registryType, string registryAction, Dictionary<string, string> registryNameValuePairs)
{
bool setupSuccessful = true;
string errMsg = "", msg1 = "", msg2 = "", indentation = String.Empty;
CommonLib.Windows.Forms.TextFormat.TextFontAndColor defaultTextProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
CommonLib.Windows.Forms.TextFormat.TextFontAndColor textProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList1 = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();
List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList2 = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();
Match regExMatch;
indentation = Common.getIndentation(1);
if (registryNameValuePairs.Count > 0)
{
foreach (KeyValuePair<string, string> entry in registryNameValuePairs)
{
msg1 = "";
if (String.Equals(registryAction, "delete", StringComparison.OrdinalIgnoreCase))
{
setupSuccessful = WindowsRegistry.DeleteRegistryValueName(registryPath, getRegistryHive(registryType), entry.Key, ref errMsg);
msg1 = "\n" + indentation + "Deleting value name " + entry.Key + " in " + registryPath;
}
else // add to registry
{
// match single-value registry value name
regExMatch = Regex.Match(entry.Value, @"^\s*value\s*:\s*(.*[^\s])\s*,\s*type\s*:\s*(.*[a-zA-Z])\s*", RegexOptions.IgnoreCase);
if (regExMatch.Success)
{
List<string> pair = new List<string>() { regExMatch.Groups[1].Value, regExMatch.Groups[2].Value };
if (getRegistryValueKind(pair[1]) != RegistryValueKind.MultiString)
setupSuccessful = WindowsRegistry.AddOrModifyRegistryKeySingleValue(registryPath, getRegistryHive(registryType), entry.Key, getRegistryValueKind(pair[1]), pair[0], ref errMsg);
else
{
setupSuccessful = false;
errMsg = "Expected a value name of type single value (string, dword, qword). Actual type is multi-string";
}
msg1 = "\n" + indentation + "Setting value name " + entry.Key + "=" + pair[0] + " in " + registryPath;
}
else
{
// match multi-string registry value name
regExMatch = Regex.Match(entry.Value, @"^(\s*:\s*value\s*:\s*.*[^\s])\s*,\s*type\s*:\s*(.*[a-zA-Z])\s*", RegexOptions.IgnoreCase);
if (regExMatch.Success)
{
List<string> pair = new List<string>() { regExMatch.Groups[1].Value, regExMatch.Groups[2].Value };
List<string> values = new List<string>(regExMatch.Groups[1].Value.Split(new string[] { ":value:" }, StringSplitOptions.RemoveEmptyEntries));
if (getRegistryValueKind(pair[1]) == RegistryValueKind.MultiString)
{
setupSuccessful = WindowsRegistry.AddOrModifyRegistryKeyMultiStringValue(registryPath, getRegistryHive(registryType), entry.Key, values, ref errMsg);
}
else
{
setupSuccessful = false;
errMsg = "Expected a value name of type multi-string. Actual type is single value (string, qword, dword)";
}
msg1 = "\n" + indentation + "Setting value name " + entry.Key + "={";
string tempStr = "";
foreach (string val in values)
{
if (tempStr.Length > 0)
tempStr += ";";
tempStr += val;
}
msg1 += tempStr + "} in " + registryPath;
}
}
}
if ( msg1.Length > 0 )
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Color.FromArgb(233, 31, 195);
textProp.wordIndex = 3;
textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg1, "in " + registryPath) - textProp.wordIndex;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList1.Add(textProp);
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Color.FromArgb(233, 31, 195);
textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg1, "in " + registryPath) + 1;
textProp.wordCount = 100;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList1.Add(textProp);
if (errMsg.Length > 0 && !setupSuccessful)
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.FAILURE);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList2.Add(textProp);
msg2 = " - FAILED. " + errMsg;
}
else if (errMsg.Length > 0)
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList2.Add(textProp);
msg2 = " - SKIPPED. " + errMsg;
}
else
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SUCCESS);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList2.Add(textProp);
msg2 = " - SUCCESS.";
}
UpdateStatusDisplayAndLogEvent(msg1, msg1, textPropList1);
UpdateStatusDisplayAndLogEvent(msg2, msg2, textPropList2);
}
if (!setupSuccessful)
break;
}
}
else // add/delete registry path
{
if (String.Equals(registryAction, "delete", StringComparison.OrdinalIgnoreCase))
{
setupSuccessful = WindowsRegistry.DeleteRegistryKey(registryPath, getRegistryHive(registryType), ref errMsg);
msg1 = "\n" + indentation + "Deleting key " + registryPath;
}
else // add name/value to registry key
{
// only creating path
setupSuccessful = WindowsRegistry.AddOrModifyRegistryKeySingleValue(registryPath, getRegistryHive(registryType), "", RegistryValueKind.String, "", ref errMsg);
msg1 = "\n" + indentation + "Creating key " + registryPath;
}
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Color.FromArgb(233, 31, 195);
textProp.wordIndex = 2;
textProp.wordCount = 100;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList1.Add(textProp);
if (errMsg.Length > 0 && !setupSuccessful)
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.FAILURE);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList2.Add(textProp);
msg2 = " - FAILED. " + errMsg;
}
else if (errMsg.Length > 0)
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList2.Add(textProp);
msg2 = " - SKIPPED. " + errMsg;
}
else
{
// set font to default text and color
textProp.textFont = defaultTextProp.textFont;
textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SUCCESS);
textProp.wordIndex = 0;
textProp.wordCount = 2;
// set font style
textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
textPropList2.Add(textProp);
msg2 = " - SUCCESS.";
}
UpdateStatusDisplayAndLogEvent(msg1, msg1, textPropList1);
UpdateStatusDisplayAndLogEvent(msg2, msg2, textPropList2);
}
return setupSuccessful;
}
public RegistryValueKind getRegistryValueKind(string valueKind)
{
RegistryValueKind regValueKind = RegistryValueKind.String;
if (String.Equals(valueKind, WindowsRegistry.valueKind.DWORD.ToString(), StringComparison.OrdinalIgnoreCase))
{
regValueKind = RegistryValueKind.DWord;
}
else if (String.Equals(valueKind, WindowsRegistry.valueKind.QWORD.ToString(), StringComparison.OrdinalIgnoreCase))
{
regValueKind = RegistryValueKind.QWord;
}
else if (String.Equals(valueKind, WindowsRegistry.valueKind.MULTI_STRING.ToString(), StringComparison.OrdinalIgnoreCase))
{
regValueKind = RegistryValueKind.MultiString;
}
return regValueKind;
}
public void getRegistryInfo(List<ConfigFileManager.Ini_KeyValue<string>> iniKeys, ref string action,
ref string registryType, Dictionary<string,string> nameValuePairs)
{
Match regExMatch;
registryType = "";
action = "";
// for every key specified for the app to be installed/checked
foreach (ConfigFileManager.Ini_KeyValue<string> iniKey in iniKeys)
{
if (Regex.IsMatch(iniKey.iniKeyName, @"reg\d+_action$", RegexOptions.IgnoreCase))
{
action = iniKey.iniValue;
}
else if (Regex.IsMatch(iniKey.iniKeyName, @"reg\d+_type", RegexOptions.IgnoreCase))
{
registryType = iniKey.iniValue;
}
else if (Regex.IsMatch(iniKey.iniKeyName, @"reg\d+_name_value_pair", RegexOptions.IgnoreCase))
{
regExMatch = Regex.Match(iniKey.iniValue, @"\[\s*name\s*:\s*(.*[^\s])\s*,\s*value\s*:\s*(.*[^\s])\s*,\s*type\s*:\s*(.*[a-zA-Z])\s*\]", RegexOptions.IgnoreCase);
if (regExMatch.Success)
{
if (!nameValuePairs.ContainsKey(regExMatch.Groups[1].Value))
{
nameValuePairs[regExMatch.Groups[1].Value] = "value:" + regExMatch.Groups[2].Value + ",type:" + regExMatch.Groups[3].Value;
}
}
else
{
regExMatch = Regex.Match(iniKey.iniValue, @"\[\s*name\s*:\s*([^,]*[^\s,])\s*\]", RegexOptions.IgnoreCase);
if (regExMatch.Success)
{
if (!nameValuePairs.ContainsKey(regExMatch.Groups[1].Value))
{
nameValuePairs[regExMatch.Groups[1].Value] = "";
}
}
}
if (!regExMatch.Success)
{
regExMatch = Regex.Match(iniKey.iniValue, @"\[\s*name\s*:\s*(.*[^\s])\s*,\s*:\s*value\s*:\s*(.*[^\s])\s*,\s*type\s*:\s*(.*[a-zA-Z])\s*\]", RegexOptions.IgnoreCase);
if (regExMatch.Success)
{
if (!nameValuePairs.ContainsKey(regExMatch.Groups[1].Value))
{
nameValuePairs[regExMatch.Groups[1].Value] = ":value:" + regExMatch.Groups[2].Value + ",type:" + regExMatch.Groups[3].Value;
}
}
}
}
}
}
public static bool registryTypeIsValid(string regType)
{
bool isValid = false;
if (String.Equals(regType, "local_machine", StringComparison.OrdinalIgnoreCase)
||
String.Equals(regType, "classes_root", StringComparison.OrdinalIgnoreCase)
||
String.Equals(regType, "current_user", StringComparison.OrdinalIgnoreCase))
{
isValid = true;
}
return isValid;
}
public static RegistryHive getRegistryHive(string regType)
{
RegistryHive regHive = RegistryHive.LocalMachine;
if (String.Equals(regType, "local_machine", StringComparison.OrdinalIgnoreCase))
regHive = RegistryHive.LocalMachine;
else if (String.Equals(regType, "classes_root", StringComparison.OrdinalIgnoreCase))
regHive = RegistryHive.ClassesRoot;
else if (String.Equals(regType, "current_user", StringComparison.OrdinalIgnoreCase))
regHive = RegistryHive.CurrentUser;
else
regHive = RegistryHive.LocalMachine;
return regHive;
}
bool verifyConfigInfo()
{
bool setupSuccessful = true;
ConfigFileManager.Ini_KeyValue<string> iniVal = new ConfigFileManager.Ini_KeyValue<string>("");
string indentation = String.Empty;
string msg;
Match regExMatch;
List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();
string registryAction = "";
string regId = "";
bool registryActionDefined = false;
bool registryTypeDefined = false;
// for every registry path defined
foreach (KeyValuePair<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> entry in regPathToVariousThings)
{
registryActionDefined = false;
registryTypeDefined = false;
// for every key specified for this registry path
foreach (ConfigFileManager.Ini_KeyValue<string> iniKey in entry.Value)
{
regExMatch = Regex.Match(iniKey.iniKeyName, @"(reg\d+)_.+$", RegexOptions.IgnoreCase);
if (regExMatch.Success)
regId = regExMatch.Groups[1].Value;
if (Regex.IsMatch(iniKey.iniKeyName, @"reg\d+_action", RegexOptions.IgnoreCase))
{
registryActionDefined = true;
registryAction = iniKey.iniValue;
}
else if (Regex.IsMatch(iniKey.iniKeyName, @"reg\d+_type", RegexOptions.IgnoreCase))
{
registryTypeDefined = true;
if (!registryTypeIsValid(iniKey.iniValue))
{
indentation = Common.getIndentation(1);
msg = "\n" + indentation + "- FAILED. "
+ "\n" + indentation + "File: " + ConfigFileManager.ms_configGeneralInfo.pathAndNameOfConfigFile
+ "\n" + indentation + "Section: " + iniKey.iniSectionName
+ "\n" + indentation + "Key: " + iniKey.iniKeyName
+ "\n" + indentation + "Value: " + iniKey.iniValue
+ "\n" + indentation + "Error Description: The value is invalid the INI file.";
Common.formatConfigIniFailureMessage(msg, textPropList);
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
setupSuccessful = false;
break;
}
}
}
if (registryActionDefined)
{
// for every key specified to be added/modified/delete
foreach (ConfigFileManager.Ini_KeyValue<string> iniKey in entry.Value)
{
if (Regex.IsMatch(iniKey.iniKeyName, @"reg\d+_name_value_pair", RegexOptions.IgnoreCase))
{
if (String.Equals(registryAction, "delete", StringComparison.OrdinalIgnoreCase))
{
regExMatch = Regex.Match(iniKey.iniValue, @"\[\s*name\s*:\s*([^,]*[^\s,])\s*\]", RegexOptions.IgnoreCase);
}
else
{
// match single value
regExMatch = Regex.Match(iniKey.iniValue, @"\[\s*name\s*:\s*(.*[^\s])\s*,\s*value\s*:\s*(.*[^\s])\s*,\s*type\s*:\s*(.*[a-zA-Z])\s*\]", RegexOptions.IgnoreCase);
// match multi value
if ( !regExMatch.Success )
regExMatch = Regex.Match(iniKey.iniValue, @"\[\s*name\s*:\s*(.*[^\s])\s*,\s*:\s*value\s*:\s*(.*[^\s])\s*,\s*type\s*:\s*(.*[a-zA-Z])\s*\]", RegexOptions.IgnoreCase);
}
if (!regExMatch.Success)
{
indentation = Common.getIndentation(1);
msg = "\n" + indentation + "- FAILED. "
+ "\n" + indentation + "File: " + ConfigFileManager.ms_configGeneralInfo.pathAndNameOfConfigFile
+ "\n" + indentation + "Section: " + iniKey.iniSectionName
+ "\n" + indentation + "Key: " + iniKey.iniKeyName
+ "\n" + indentation + "Value: " + iniKey.iniValue
+ "\n" + indentation + "Error Description: The value is invalid the INI file.";
Common.formatConfigIniFailureMessage(msg, textPropList);
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
setupSuccessful = false;
break;
}
}
}
}
if (!setupSuccessful)
break;
if (!registryActionDefined)
{
indentation = Common.getIndentation(1);
msg = "\n" + indentation + "- FAILED. "
+ "\n" + indentation + "File: " + ConfigFileManager.ms_configGeneralInfo.pathAndNameOfConfigFile
+ "\n" + indentation + "Section: " + entry.Key.iniSectionName
+ "\n" + indentation + "Error Description: The key name " + regId + "_action is missing in the above section in the INI file.";
Common.formatConfigIniFailureMessage(msg, textPropList);
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
setupSuccessful = false;
break;
}
else if (!registryTypeDefined)
{
indentation = Common.getIndentation(1);
msg = "\n" + indentation + "- FAILED. "
+ "\n" + indentation + "File: " + ConfigFileManager.ms_configGeneralInfo.pathAndNameOfConfigFile
+ "\n" + indentation + "Section: " + entry.Key.iniSectionName
+ "\n" + indentation + "Error Description: The key name " + regId + "_type is missing in the above section in the INI file.";
Common.formatConfigIniFailureMessage(msg, textPropList);
UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
setupSuccessful = false;
break;
}
}
return setupSuccessful;
}
}
}