using System; using System.Collections; using System.ComponentModel; using System.Globalization; using System.IO; using System.Reflection; using System.Windows.Forms; namespace Microsoft.Samples.AppUpdater { public class AppUpdater : Component, ISupportInitialize { public delegate bool CheckForUpdateEventHandler(object sender, EventArgs e); public delegate void UpdateDetectedEventHandler(object sender, UpdateDetectedEventArgs e); public delegate void UpdateCompleteEventHandler(object sender, UpdateCompleteEventArgs e); public delegate void NotifyUpdateFileInfoEventHandler(object sender, NotifyUpdateFileInfoEventArgs e); public const int RestartAppReturnValue = 2; private Container components; private bool LoadingAssembly; private Control EventControl; internal AppManifest Manifest; private AppDownloader _Downloader; private ServerPoller _Poller; private string _UpdateUrl = "http://localhost/"; private ChangeDetectionModes _ChangeDetectionMode = ChangeDetectionModes.DirectFileCheck; private bool _ShowDefaultUI; private bool _AutoFileLoad; [Category("AppUpdate Configuration")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [Description("The object that downloads and installs new updates.")] [TypeConverter(typeof(ExpandableObjectConverter))] public AppDownloader Downloader { get { return _Downloader; } set { _Downloader = value; } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [TypeConverter(typeof(ExpandableObjectConverter))] [Description("The object that periodically polls for new updates.")] [Category("AppUpdate Configuration")] public ServerPoller Poller { get { return _Poller; } set { _Poller = value; } } [Category("AppUpdate Configuration")] [Description("The Url to download updates from.")] [DefaultValue("http://localhost/")] public string UpdateUrl { get { return _UpdateUrl; } set { _UpdateUrl = value; } } [Category("AppUpdate Configuration")] [Description("The way to detect new updates.")] [DefaultValue(ChangeDetectionModes.DirectFileCheck)] public ChangeDetectionModes ChangeDetectionMode { get { return _ChangeDetectionMode; } set { _ChangeDetectionMode = value; } } [Category("AppUpdate Configuration")] [Description("Determines whether the default UI is shown or supressed.")] [DefaultValue(false)] public bool ShowDefaultUI { get { return _ShowDefaultUI; } set { _ShowDefaultUI = value; } } [DefaultValue(false)] [Description("Enables auto-download of missing assemblies.")] [Category("AppUpdate Configuration")] public bool AutoFileLoad { get { return _AutoFileLoad; } set { _AutoFileLoad = value; } } public event CheckForUpdateEventHandler OnCheckForUpdate; public event UpdateDetectedEventHandler OnUpdateDetected; public event UpdateCompleteEventHandler OnUpdateComplete; public event NotifyUpdateFileInfoEventHandler OnNotifyUpdateFileInfo; public AppUpdater() { Poller = new ServerPoller(this); Downloader = new AppDownloader(this); } public AppUpdater(IContainer container) { Poller = new ServerPoller(this); Downloader = new AppDownloader(this); container.Add(this); InitializeComponent(); } public AppUpdater(string updateUrl, ChangeDetectionModes changeDetectionMode, bool showDefaultUI, bool autoFileLoad, bool validateAssemblies) { Poller = new ServerPoller(this); Downloader = new AppDownloader(this); UpdateUrl = updateUrl; ChangeDetectionMode = changeDetectionMode; ShowDefaultUI = showDefaultUI; AutoFileLoad = autoFileLoad; Downloader.ValidateAssemblies = validateAssemblies; Initialize(); } public void BeginInit() { } public void EndInit() { if (!base.DesignMode) { Initialize(); } } private void InitializeComponent() { components = new Container(); } public void Initialize() { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\"; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location); fileNameWithoutExtension += ".xml"; path = Path.Combine(path, fileNameWithoutExtension); Manifest = AppManifest.Load(path); if (ChangeDetectionMode == ChangeDetectionModes.DirectFileCheck) { EnableManifestGeneration(); } if (AutoFileLoad) { EnableFileAutoLoad(); } if (Poller.AutoStart) { Poller.Start(); } Downloader.OnUpdateComplete += OnDownloaderComplete; Downloader.OnNotifyUpdateFileInfo += OnDownloaderUpdateFileInfo; Application.ApplicationExit += OnApplicationExit; EventControl = new Control(); _ = EventControl.Handle; if (Manifest.State.Phase != 0) { Downloader.Start(); } } public void DownloadUpdate() { Downloader.Start(); } public bool CheckForUpdates() { bool flag = false; if (this.OnCheckForUpdate != null) { flag = this.OnCheckForUpdate(this, new EventArgs()); } else if (ChangeDetectionMode == ChangeDetectionModes.ServerManifestCheck) { ServerManifest serverManifest = new ServerManifest(); serverManifest.Load(UpdateUrl); flag = serverManifest.IsServerVersionNewer(GetLatestInstalledVersion()); } else { foreach (object resource2 in Manifest.Resources.ResourceList) { Resource resource = (Resource)((DictionaryEntry)resource2).Value; string url = UpdateUrl + resource.Name; string filePath = resource.FilePath; if (WebFileLoader.CheckForFileUpdate(url, filePath)) { flag = true; } } } if (this.OnUpdateDetected != null) { Delegate[] invocationList = this.OnUpdateDetected.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { UpdateDetectedEventHandler method = (UpdateDetectedEventHandler)invocationList[i]; UpdateDetectedEventArgs updateDetectedEventArgs = new UpdateDetectedEventArgs(); updateDetectedEventArgs.HasNewVersion = flag; EventControl.BeginInvoke(method, this, updateDetectedEventArgs); } } return flag; } public static Version GetLatestInstalledVersion() { string directoryName = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); directoryName = Path.Combine(Directory.GetParent(directoryName).FullName, "AppStart.config"); AppStartConfig appStartConfig = AppStartConfig.Load(directoryName); AssemblyName assemblyName = AssemblyName.GetAssemblyName(appStartConfig.AppExePath); return assemblyName.Version; } public void RestartApp() { Environment.ExitCode = 2; Application.Exit(); Poller.Stop(); Downloader.Stop(); } private void OnDownloaderComplete(object sender, UpdateCompleteEventArgs args) { if (this.OnUpdateComplete != null) { Delegate[] invocationList = this.OnUpdateComplete.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { UpdateCompleteEventHandler method = (UpdateCompleteEventHandler)invocationList[i]; EventControl.BeginInvoke(method, sender, args); } } EventControl.BeginInvoke(new UpdateCompleteEventHandler(UpdateCompleteOps), sender, args); } private void OnDownloaderUpdateFileInfo(object sender, NotifyUpdateFileInfoEventArgs args) { if (this.OnUpdateComplete != null) { Delegate[] invocationList = this.OnNotifyUpdateFileInfo.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { NotifyUpdateFileInfoEventHandler method = (NotifyUpdateFileInfoEventHandler)invocationList[i]; EventControl.BeginInvoke(method, sender, args); } } } private void UpdateCompleteOps(object sender, UpdateCompleteEventArgs args) { if (!ShowDefaultUI) { return; } if (args.UpdateSucceeded) { UpdateForm updateForm = new UpdateForm(); if (updateForm.ShowDialog() == DialogResult.Yes) { RestartApp(); } } else { string text = "The auto-update of this application failed with the following error message: \r\n\r\n" + args.ErrorMessage + "\r\n\r\nTo correct this problem, try rebooting the computer & re-launching this application."; MessageBox.Show(text, "Application Update Failed", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) { string[] array = args.LoadedAssembly.Location.Split('\\'); int num = array.Length - 1; string name = array[num]; if (!Manifest.Resources.ResourceExists(name) && IsLocalAssembly(args.LoadedAssembly)) { Resource resource = new Resource(); resource.FilePath = args.LoadedAssembly.Location; resource.Name = name; resource.AddedAtRuntime = true; Manifest.Resources.AddResource(resource); Manifest.Update(); } } private Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) { if (LoadingAssembly) { return null; } LoadingAssembly = true; string[] array = args.Name.Split(new char[1] { ',' }, 2); string text = array[0] + ".dll"; string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, text); string text2; if (ChangeDetectionMode == ChangeDetectionModes.DirectFileCheck) { text2 = UpdateUrl + text; } else { ServerManifest serverManifest = new ServerManifest(); serverManifest.Load(UpdateUrl); text2 = Path.Combine(serverManifest.ApplicationUrl, text); } try { WebFileLoader.UpdateFile(text2, filePath); } catch (Exception) { if (ShowDefaultUI) { MessageBox.Show("Unable to auto-download the missing parts of the application from:\r\n" + text2 + "\r\n\r\nMake sure your connected to the network. If the problem persists re-install the application."); } return null; } try { return Assembly.Load(args.Name); } catch (Exception) { return null; } finally { LoadingAssembly = false; } } private bool IsLocalAssembly(Assembly assembly) { string text = assembly.Location.Replace("/", "\\").ToLower(new CultureInfo("en-US")); string text2 = AppDomain.CurrentDomain.BaseDirectory.ToLower(new CultureInfo("en-US")); if (text.StartsWith(text2.ToLower(new CultureInfo("en-US"))) && !assembly.FullName.StartsWith("AppManager")) { return true; } return false; } private void OnApplicationExit(object sender, EventArgs args) { Poller.Stop(); Downloader.Stop(); } private void EnableFileAutoLoad() { AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += OnAssemblyResolve; } private void DisableFileAutoLoad() { AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve -= OnAssemblyResolve; } private void EnableManifestGeneration() { AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyLoad += OnAssemblyLoad; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (IsLocalAssembly(assemblies[i])) { Resource resource = new Resource(); string[] array = assemblies[i].Location.Split('\\'); int num = array.Length - 1; resource.FilePath = assemblies[i].Location; resource.Name = array[num]; resource.AddedAtRuntime = true; Manifest.Resources.AddResource(resource); Manifest.Update(); } } } private void DisableManifestGeneration() { AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyLoad -= OnAssemblyLoad; } } }