public static int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.InstallDuring) { // If the update is disabled, go straight in if (DISABLE_UPDATE_DOMAIN) { return(RunMethod(method, cmdargs)); } // If we are not the primary domain, just execute if (!AppDomain.CurrentDomain.IsDefaultAppDomain()) { int r = 0; WrapWithUpdater(defaultstrategy, () => { r = RunMethod(method, cmdargs); }); return(r); } // If we are a re-launch, wait briefly for the other process to exit var sleepmarker = System.Environment.GetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME)); if (!string.IsNullOrWhiteSpace(sleepmarker)) { System.Environment.SetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME), null); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10)); } // Check if there are updates installed, otherwise use current KeyValuePair <string, UpdateInfo> best = new KeyValuePair <string, UpdateInfo>(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, SelfVersion); if (HasUpdateInstalled) { best = m_hasUpdateInstalled.Value; } if (INSTALLDIR != null && System.IO.File.Exists(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE))) { try { var current = System.IO.File.ReadAllText(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE)).Trim(); if (!string.IsNullOrWhiteSpace(current)) { var targetfolder = System.IO.Path.Combine(INSTALLDIR, current); var currentmanifest = ReadInstalledManifest(targetfolder); if (currentmanifest != null && VerifyUnpackedFolder(targetfolder, currentmanifest)) { best = new KeyValuePair <string, UpdateInfo>(targetfolder, currentmanifest); } } } catch (Exception ex) { if (OnError != null) { OnError(ex); } } } Environment.SetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME), InstalledBaseDir); var folder = best.Key; // Basic idea with the loop is that the running AppDomain can use // RUN_UPDATED_ENVNAME_TEMPLATE to signal that a new version is ready // when the caller exits, the new update is executed // // This allows more or less seamless updates // int result = 0; while (!string.IsNullOrWhiteSpace(folder) && System.IO.Directory.Exists(folder)) { var prevfolder = folder; // Create the new domain var domain = AppDomain.CreateDomain( "UpdateDomain", null, folder, "", false ); result = domain.ExecuteAssemblyByName(method.DeclaringType.Assembly.GetName().Name, cmdargs); folder = (string)domain.GetData(RUN_UPDATED_FOLDER_PATH); try { AppDomain.Unload(domain); } catch (Exception ex) { Console.WriteLine("Appdomain unload error: {0}", ex); } if (!string.IsNullOrWhiteSpace(folder)) { if (!VerifyUnpackedFolder(folder)) { folder = prevfolder; //Go back and run the previous version } else if (RequiresRespawn) { // We have a valid update, and the current instance is terminated. // But due to external libraries, we need to re-spawn the original process try { var args = Environment.CommandLine; var app = Environment.GetCommandLineArgs().First(); args = args.Substring(app.Length); if (!System.IO.Path.IsPathRooted(app)) { app = System.IO.Path.Combine(InstalledBaseDir, app); } // Re-launch but give the OS a little time to fully unload all open handles, etc. var si = new System.Diagnostics.ProcessStartInfo(app, args); si.UseShellExecute = false; si.EnvironmentVariables.Add(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME), "1"); System.Diagnostics.Process.Start(si); return(0); } catch (Exception ex) { if (OnError != null) { OnError(ex); } folder = prevfolder; } } } } return(result); }
private static void WrapWithUpdater(AutoUpdateStrategy defaultstrategy, Action wrappedFunction) { string optstr = Environment.GetEnvironmentVariable(string.Format(UPDATE_STRATEGY_ENVNAME_TEMPLATE, APPNAME)); AutoUpdateStrategy strategy; if (string.IsNullOrWhiteSpace(optstr) || !Enum.TryParse(optstr, out strategy)) strategy = defaultstrategy; System.Threading.Thread backgroundChecker = null; UpdateInfo updateDetected = null; bool updateInstalled = false; bool checkForUpdate; bool downloadUpdate; bool runAfter; bool runDuring; bool runBefore; switch (strategy) { case AutoUpdateStrategy.CheckBefore: case AutoUpdateStrategy.CheckDuring: case AutoUpdateStrategy.CheckAfter: checkForUpdate = true; downloadUpdate = false; break; case AutoUpdateStrategy.InstallBefore: case AutoUpdateStrategy.InstallDuring: case AutoUpdateStrategy.InstallAfter: checkForUpdate = true; downloadUpdate = true; break; default: checkForUpdate = false; downloadUpdate = false; break; } switch (strategy) { case AutoUpdateStrategy.CheckBefore: case AutoUpdateStrategy.InstallBefore: runBefore = true; runDuring = false; runAfter = false; break; case AutoUpdateStrategy.CheckAfter: case AutoUpdateStrategy.InstallAfter: runBefore = false; runDuring = false; runAfter = true; break; case AutoUpdateStrategy.CheckDuring: case AutoUpdateStrategy.InstallDuring: runBefore = false; runDuring = true; runAfter = false; break; default: runBefore = false; runDuring = false; runAfter = false; break; } if (checkForUpdate) { backgroundChecker = new System.Threading.Thread(() => { // Don't run "during" if the task is short if (runDuring) System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10)); updateDetected = CheckForUpdate(); if (updateDetected != null && downloadUpdate) { if (!runDuring) Console.WriteLine("Update to {0} detected, installing...", updateDetected.Displayname); updateInstalled = DownloadAndUnpackUpdate(updateDetected); } }); backgroundChecker.IsBackground = true; backgroundChecker.Name = "BackgroundUpdateChecker"; if (!runAfter) backgroundChecker.Start(); if (runBefore) { Console.WriteLine("Checking for update ..."); backgroundChecker.Join(); if (downloadUpdate) { if (updateInstalled) Console.WriteLine("Install succeeded, running updated version"); else Console.WriteLine("Install or download failed, using current version"); } else if (updateDetected != null) { Console.WriteLine("Update \"{0}\" detected", updateDetected.Displayname); } backgroundChecker = null; } } wrappedFunction(); if (backgroundChecker != null && runAfter) { Console.WriteLine("Checking for update ..."); backgroundChecker.Start(); backgroundChecker.Join(); } if (backgroundChecker != null && updateDetected != null) { if (backgroundChecker.IsAlive) { Console.WriteLine("Waiting for update \"{0}\" to complete", updateDetected.Displayname); backgroundChecker.Join(); } if (downloadUpdate) { if (updateInstalled) Console.WriteLine("Install succeeded, running updated version on next launch"); else Console.WriteLine("Install or download failed, using current version on next launch"); } else { Console.WriteLine("Update \"{0}\" detected", updateDetected.Displayname); } } }
private static void WrapWithUpdater(AutoUpdateStrategy defaultstrategy, Action wrappedFunction) { string optstr = Environment.GetEnvironmentVariable(string.Format(UPDATE_STRATEGY_ENVNAME_TEMPLATE, APPNAME)); AutoUpdateStrategy strategy; if (string.IsNullOrWhiteSpace(optstr) || !Enum.TryParse(optstr, out strategy)) { strategy = defaultstrategy; } System.Threading.Thread backgroundChecker = null; UpdateInfo updateDetected = null; bool updateInstalled = false; bool checkForUpdate; bool downloadUpdate; bool runAfter; bool runDuring; bool runBefore; switch (strategy) { case AutoUpdateStrategy.CheckBefore: case AutoUpdateStrategy.CheckDuring: case AutoUpdateStrategy.CheckAfter: checkForUpdate = true; downloadUpdate = false; break; case AutoUpdateStrategy.InstallBefore: case AutoUpdateStrategy.InstallDuring: case AutoUpdateStrategy.InstallAfter: checkForUpdate = true; downloadUpdate = true; break; default: checkForUpdate = false; downloadUpdate = false; break; } switch (strategy) { case AutoUpdateStrategy.CheckBefore: case AutoUpdateStrategy.InstallBefore: runBefore = true; runDuring = false; runAfter = false; break; case AutoUpdateStrategy.CheckAfter: case AutoUpdateStrategy.InstallAfter: runBefore = false; runDuring = false; runAfter = true; break; case AutoUpdateStrategy.CheckDuring: case AutoUpdateStrategy.InstallDuring: runBefore = false; runDuring = true; runAfter = false; break; default: runBefore = false; runDuring = false; runAfter = false; break; } if (checkForUpdate) { backgroundChecker = new System.Threading.Thread(() => { // Don't run "during" if the task is short if (runDuring) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10)); } updateDetected = CheckForUpdate(); if (updateDetected != null && downloadUpdate) { if (!runDuring) { Console.WriteLine("Update to {0} detected, installing...", updateDetected.Displayname); } updateInstalled = DownloadAndUnpackUpdate(updateDetected); } }); backgroundChecker.IsBackground = true; backgroundChecker.Name = "BackgroundUpdateChecker"; if (!runAfter) { backgroundChecker.Start(); } if (runBefore) { Console.WriteLine("Checking for update ..."); backgroundChecker.Join(); if (downloadUpdate) { if (updateInstalled) { Console.WriteLine("Install succeeded, running updated version"); } else { Console.WriteLine("Install or download failed, using current version"); } } else if (updateDetected != null) { Console.WriteLine("Update \"{0}\" detected", updateDetected.Displayname); } backgroundChecker = null; } } wrappedFunction(); if (backgroundChecker != null && runAfter) { Console.WriteLine("Checking for update ..."); backgroundChecker.Start(); backgroundChecker.Join(); } if (backgroundChecker != null && updateDetected != null) { if (backgroundChecker.IsAlive) { Console.WriteLine("Waiting for update \"{0}\" to complete", updateDetected.Displayname); backgroundChecker.Join(); } if (downloadUpdate) { if (updateInstalled) { Console.WriteLine("Install succeeded, running updated version on next launch"); } else { Console.WriteLine("Install or download failed, using current version on next launch"); } } else { Console.WriteLine("Update \"{0}\" detected", updateDetected.Displayname); } } }
public static int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.CheckDuring) { // If the update is disabled, go straight in if (DISABLE_UPDATE_DOMAIN) return RunMethod(method, cmdargs); // If we are not the primary domain, just execute if (!AppDomain.CurrentDomain.IsDefaultAppDomain()) { int r = 0; WrapWithUpdater(defaultstrategy, () => { r = RunMethod(method, cmdargs); }); return r; } // If we are a re-launch, wait briefly for the other process to exit var sleepmarker = System.Environment.GetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME)); if (!string.IsNullOrWhiteSpace(sleepmarker)) { System.Environment.SetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME), null); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10)); } // Check if there are updates installed, otherwise use current KeyValuePair<string, UpdateInfo> best = new KeyValuePair<string, UpdateInfo>(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, SelfVersion); if (HasUpdateInstalled) best = m_hasUpdateInstalled.Value; if (INSTALLDIR != null && System.IO.File.Exists(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE))) { try { var current = System.IO.File.ReadAllText(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE)).Trim(); if (!string.IsNullOrWhiteSpace(current)) { var targetfolder = System.IO.Path.Combine(INSTALLDIR, current); var currentmanifest = ReadInstalledManifest(targetfolder); if (currentmanifest != null && VerifyUnpackedFolder(targetfolder, currentmanifest)) best = new KeyValuePair<string, UpdateInfo>(targetfolder, currentmanifest); } } catch (Exception ex) { if (OnError != null) OnError(ex); } } Environment.SetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME), InstalledBaseDir); var folder = best.Key; // Basic idea with the loop is that the running AppDomain can use // RUN_UPDATED_ENVNAME_TEMPLATE to signal that a new version is ready // when the caller exits, the new update is executed // // This allows more or less seamless updates // int result = 0; while (!string.IsNullOrWhiteSpace(folder) && System.IO.Directory.Exists(folder)) { var prevfolder = folder; // Create the new domain var domain = AppDomain.CreateDomain( "UpdateDomain", null, folder, "", false ); result = domain.ExecuteAssemblyByName(method.DeclaringType.Assembly.GetName().Name, cmdargs); folder = (string)domain.GetData(RUN_UPDATED_FOLDER_PATH); try { AppDomain.Unload(domain); } catch (Exception ex) { Console.WriteLine("Appdomain unload error: {0}", ex); } if (!string.IsNullOrWhiteSpace(folder)) { if (!VerifyUnpackedFolder(folder)) folder = prevfolder; //Go back and run the previous version else if (RequiresRespawn) { // We have a valid update, and the current instance is terminated. // But due to external libraries, we need to re-spawn the original process try { var args = Environment.CommandLine; var app = Environment.GetCommandLineArgs().First(); args = args.Substring(app.Length); if (!System.IO.Path.IsPathRooted(app)) app = System.IO.Path.Combine(InstalledBaseDir, app); // Re-launch but give the OS a little time to fully unload all open handles, etc. var si = new System.Diagnostics.ProcessStartInfo(app, args); si.UseShellExecute = false; si.EnvironmentVariables.Add(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME), "1"); System.Diagnostics.Process.Start(si); return 0; } catch (Exception ex) { if (OnError != null) OnError(ex); folder = prevfolder; } } } } return result; }