using System; using System.Collections.Generic; using System.Text; using Microsoft.Win32; using System.IO; using System.Diagnostics; namespace SL_Switcher { public class ProgressEventArgs : EventArgs { public int Progress; public int Max; public string Message; public ProgressEventArgs(int progress, int max) { this.Progress = progress; this.Max = max; } public ProgressEventArgs(int progress, int max, string message) : this(progress,max) { this.Message = message; } } public delegate void OperationDelegate(object sender, EventArgs e); public delegate void OperationProgressDelegate(object sender, ProgressEventArgs e); class Switcher { private const string LL_COMPANY_NAME = "Linden Research, Inc."; private const string DG_COMPANY_NAME = "Dale Glass"; private List m_versions; public OperationDelegate WorkStarted; public OperationDelegate WorkFinished; public OperationProgressDelegate Progress; private string m_root_path; private string m_originals_path; private string m_thirdparty_path; private string m_run_path; public Switcher(string root_path) { m_versions = new List(); m_root_path = root_path; m_originals_path = Path.Combine(m_root_path, "LL"); m_thirdparty_path = Path.Combine(m_root_path, "ThirdParty"); m_run_path = Path.Combine(m_root_path, "Run"); Console.WriteLine("Root: {0}", m_root_path); } public void DetectInstalled() { Console.WriteLine("Detecting installed versions..."); DetectedVersions.Clear(); RegistryKey root = Registry.LocalMachine.OpenSubKey("SOFTWARE"); root = root.OpenSubKey(DG_COMPANY_NAME);if (root == null) return; root = root.OpenSubKey("SL Switcher"); if (root == null) return; ScanKey(root.OpenSubKey("Third Party"), false); ScanKey(root.OpenSubKey("Official"), true); } public void ScanKey(RegistryKey root, bool is_official) { if (root == null) return; Console.WriteLine("Scanning key {0}...", root); foreach (string vendor in root.GetSubKeyNames()) { RegistryKey vkey = root.OpenSubKey(vendor); foreach (string product in vkey.GetSubKeyNames()) { RegistryKey pkey = vkey.OpenSubKey(product); Program prog; if (is_official) { prog = new OfficialProgram(pkey, vendor, product); } else { prog = new ThirdPartyProgram(pkey, vendor, product); } DetectedVersions.Add(prog); } } } public void LaunchVersion(Program prog) { if (prog is OfficialProgram) { LaunchVersion((OfficialProgram)prog); } else if (prog is ThirdPartyProgram) { LaunchVersion((ThirdPartyProgram)prog); } else { throw new Exception("Internal error: Unrecognized program type"); } } public void LaunchVersion(OfficialProgram prog) { if (prog is OfficialProgram) { Launch(prog, prog.CachedPath); return; } } public void LaunchVersion(ThirdPartyProgram prog) { Program orig_ver = null; Console.WriteLine("Attempting to launch " + prog.ToString()); foreach (string base_ver in prog.AcceptedBaseVersions) { foreach (Program p in DetectedVersions) { if (p is OfficialProgram && p.AppVersion == base_ver) { Console.WriteLine("Found parent: " + p.ToString()); orig_ver = p; break; } } } if (orig_ver == null) { throw new Exception("Required SL version not found. Accepted one of: " + prog.AcceptedBaseVersionsAsString); } NotifyStarted(); NotifyProgress(0, 1, "Building file list"); List ops = new List(); ops = ListBuilder.Build(orig_ver.CachedPath, prog.CachedPath, m_run_path); // Calculate total int total = CalculateTotal(ops); int progress = 0; // Do work foreach (FileOperation op in ops) { op.Execute(); progress += op.ProgressValue; NotifyProgress(progress, total, "Copying files"); } NotifyFinished(); Launch(prog, m_run_path); } private int CalculateTotal(List ops) { int ret = 0; foreach (FileOperation op in ops) { ret += op.ProgressValue; } return ret; } private void Launch(Program ver, string runpath) { ProcessStartInfo info = new ProcessStartInfo(); info.FileName = Path.Combine(runpath, ver.Executable); info.Arguments = ver.Arguments; info.WorkingDirectory = runpath; Console.WriteLine("Running: {0} {1}" , Path.Combine(info.WorkingDirectory, info.FileName), info.Arguments); Process p = Process.Start(info); } public void InitDirectories() { Console.WriteLine("Creating directories..."); NotifyStarted(); Directory.CreateDirectory(m_root_path); Directory.CreateDirectory(m_run_path); Directory.CreateDirectory(m_originals_path); Directory.CreateDirectory(m_thirdparty_path); NotifyFinished(); } public void PrepareDirectories() { Console.WriteLine("Preparing directories..."); NotifyStarted(); int count = 0; // Build list of files to copy List processed_versions = new List(); List all_ops = new List(); // Scan registry for SL versions RegistryKey root = Registry.LocalMachine.OpenSubKey("SOFTWARE"); RegistryKey llkey = root.OpenSubKey(LL_COMPANY_NAME); if (llkey == null) return; RegistryKey dgkey = root.OpenSubKey(DG_COMPANY_NAME, true); dgkey = dgkey.CreateSubKey("SL Switcher"); dgkey = dgkey.CreateSubKey("Official").CreateSubKey(LL_COMPANY_NAME); string[] subkeys = llkey.GetSubKeyNames(); foreach(string name in subkeys) { RegistryKey verkey = llkey.OpenSubKey(name); string version = (string)verkey.GetValue("Version"); string path = (string)verkey.GetValue(null); string cached_path = Path.Combine(m_originals_path, version); // Create local registry entry for the install RegistryKey swkey = dgkey.CreateSubKey(name); swkey.SetValue("Version", version); swkey.SetValue("Path", cached_path); swkey.SetValue("Executable", verkey.GetValue("Exe")); swkey.SetValue("Arguments", verkey.GetValue("Flags")); // Stable and beta can be the same version, don't process twice if (!processed_versions.Contains(version)) { processed_versions.Add(version); Directory.CreateDirectory(cached_path); List ops = ListBuilder.Build(path, cached_path); all_ops.AddRange(ops); } NotifyProgress(++count, subkeys.GetLength(0), "Scanning directories"); } // Calculate total int total = CalculateTotal(all_ops); int progress = 0; // Do work foreach (FileOperation op in all_ops) { op.Execute(); progress += op.ProgressValue; NotifyProgress(progress, total, "Copying files"); } NotifyFinished(); } public List DetectedVersions { get { return m_versions; } set { m_versions = value; } } internal void NotifyStarted() { if (WorkStarted != null) { WorkStarted(this, new EventArgs()); } } internal void NotifyFinished() { if (WorkFinished != null) { WorkFinished(this, new EventArgs()); } } internal void NotifyProgress(int progress, int max, string msg) { if (Progress != null) { Progress(this, new ProgressEventArgs(progress,max, msg)); } } } }