diff --git a/CHANGELOG.md b/CHANGELOG.md index 60b27ff9..1263ad38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] ### Added +- #2086: Replace WebClient with async HttpClient for updater. - #1850: Minify config xml - #1770: Added missing RDP performance settings - #1516: added API to access credential vault (Thycotic Secret Server) by specifying SSAPI:ID as username @@ -38,7 +39,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - #1720: Show configuration file name in title of password prompt form - #1713: Sound redirection does not work if Clipboard redirection is set to No - #1632: 1.77.1 breaks RDP drive and sound redirection -- #1610: Menu bar changes to english when cancelling options form +- #1610: Menu bar changes to english when canceling options form - #1595: Unhandled exception when trying to browse through non existent multi ssh history with keyboard key strokes - #1589: Update SQL tables instead of rewriting them - #1465: REGRESSION: Smart Cards redirection to Remote Desktop not working diff --git a/mRemoteNG/App/Startup.cs b/mRemoteNG/App/Startup.cs index cb54bc55..e7a13bce 100644 --- a/mRemoteNG/App/Startup.cs +++ b/mRemoteNG/App/Startup.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Diagnostics; using System.Globalization; +using System.Threading.Tasks; using mRemoteNG.App.Info; using mRemoteNG.App.Initialization; using mRemoteNG.App.Update; @@ -65,7 +66,7 @@ namespace mRemoteNG.App Runtime.ConnectionsService.RemoteConnectionsSyncronizer.Enable(); } - public void CheckForUpdate() + public async Task CheckForUpdate() { if (_appUpdate == null) { @@ -87,32 +88,9 @@ namespace mRemoteNG.App return; } - _appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted; - _appUpdate.GetUpdateInfoAsync(); - } - - private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e) - { - if (_frmMain.InvokeRequired) - { - _frmMain.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), sender, e); - return; - } - try { - _appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted; - - if (e.Cancelled) - { - return; - } - - if (e.Error != null) - { - throw e.Error; - } - + await _appUpdate.GetUpdateInfoAsync(); if (_appUpdate.IsUpdateAvailable()) { Windows.Show(WindowType.Update); @@ -120,7 +98,7 @@ namespace mRemoteNG.App } catch (Exception ex) { - Runtime.MessageCollector.AddExceptionMessage("GetUpdateInfoCompleted() failed.", ex); + Runtime.MessageCollector.AddExceptionMessage("CheckForUpdate() failed.", ex); } } } diff --git a/mRemoteNG/App/Update/AppUpdater.cs b/mRemoteNG/App/Update/AppUpdater.cs index 5c21574c..4bfc6b06 100644 --- a/mRemoteNG/App/Update/AppUpdater.cs +++ b/mRemoteNG/App/Update/AppUpdater.cs @@ -1,12 +1,12 @@ using System; using System.IO; using System.Net; -using System.ComponentModel; +using System.Net.Http; using System.Threading; -using System.Reflection; using mRemoteNG.App.Info; using mRemoteNG.Security.SymmetricEncryption; using System.Security.Cryptography; +using System.Threading.Tasks; using mRemoteNG.Properties; #if !PORTABLE using mRemoteNG.Tools; @@ -21,29 +21,30 @@ namespace mRemoteNG.App.Update { public class AppUpdater { + private const int _bufferLength = 8192; private WebProxy _webProxy; - private Thread _getUpdateInfoThread; - private Thread _getChangeLogThread; + private HttpClient _httpClient; + private CancellationTokenSource _changeLogCancelToken; + private CancellationTokenSource _getUpdateInfoCancelToken; #region Public Properties public UpdateInfo CurrentUpdateInfo { get; private set; } - public string ChangeLog { get; private set; } - public bool IsGetUpdateInfoRunning { - get { return _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive; } + get + { + return _getUpdateInfoCancelToken != null; + } } private bool IsGetChangeLogRunning { - get { return _getChangeLogThread != null && _getChangeLogThread.IsAlive; } - } - - public bool IsDownloadUpdateRunning - { - get { return _downloadUpdateWebClient != null; } + get + { + return _changeLogCancelToken != null; + } } #endregion @@ -52,10 +53,10 @@ namespace mRemoteNG.App.Update public AppUpdater() { - SetProxySettings(); + SetDefaultProxySettings(); } - private void SetProxySettings() + private void SetDefaultProxySettings() { var shouldWeUseProxy = Settings.Default.UpdateUseProxy; var proxyAddress = Settings.Default.UpdateProxyAddress; @@ -78,13 +79,14 @@ namespace mRemoteNG.App.Update if (useProxy && !string.IsNullOrEmpty(address)) { _webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address); - _webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null; } else { _webProxy = null; } + + UpdateHttpClient(); } public bool IsUpdateAvailable() @@ -96,54 +98,24 @@ namespace mRemoteNG.App.Update return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion(); } - - public void GetUpdateInfoAsync() + + public async Task DownloadUpdateAsync(IProgress progress) { if (IsGetUpdateInfoRunning) { - _getUpdateInfoThread.Abort(); - } + _getUpdateInfoCancelToken.Cancel(); + _getUpdateInfoCancelToken.Dispose(); + _getUpdateInfoCancelToken = null; - _getUpdateInfoThread = new Thread(GetUpdateInfo); - _getUpdateInfoThread.SetApartmentState(ApartmentState.STA); - _getUpdateInfoThread.IsBackground = true; - _getUpdateInfoThread.Start(); - } - - public void GetChangeLogAsync() - { - if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) - { - throw new InvalidOperationException( - "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync()."); - } - - if (IsGetChangeLogRunning) - { - _getChangeLogThread.Abort(); - } - - _getChangeLogThread = new Thread(GetChangeLog); - _getChangeLogThread.SetApartmentState(ApartmentState.STA); - _getChangeLogThread.IsBackground = true; - _getChangeLogThread.Start(); - } - - public void DownloadUpdateAsync() - { - if (_downloadUpdateWebClient != null) - { throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress."); } if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid) { - throw new InvalidOperationException( - "CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); + throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync()."); } #if !PORTABLE - CurrentUpdateInfo.UpdateFilePath = - Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); + CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi")); #else var sfd = new SaveFileDialog { @@ -160,135 +132,38 @@ namespace mRemoteNG.App.Update return; } #endif - DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, - CurrentUpdateInfo.UpdateFilePath); - } - - #endregion - - #region Private Properties - - private WebClient _downloadUpdateWebClient; - - private WebClient DownloadUpdateWebClient - { - get - { - if (_downloadUpdateWebClient != null) - { - return _downloadUpdateWebClient; - } - - _downloadUpdateWebClient = CreateWebClient(); - - _downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged; - _downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted; - - return _downloadUpdateWebClient; - } - } - - #endregion - - #region Private Methods - - private WebClient CreateWebClient() - { - var webClient = new WebClient(); - webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent); - webClient.Proxy = _webProxy; - return webClient; - } - - private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result, - Exception exception, - bool cancelled, - object userToken) - { - var type = typeof(DownloadStringCompletedEventArgs); - const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance; - Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)}; - var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null); - object[] arguments = {result, exception, cancelled, userToken}; - - if (constructor == null) - return null; - return (DownloadStringCompletedEventArgs)constructor.Invoke(arguments); - } - - private DownloadStringCompletedEventArgs DownloadString(Uri address) - { - var webClient = CreateWebClient(); - var result = string.Empty; - Exception exception = null; - var cancelled = false; - try { - result = webClient.DownloadString(address); - } - catch (ThreadAbortException) - { - cancelled = true; - } - catch (Exception ex) - { - exception = ex; - } + _getUpdateInfoCancelToken = new CancellationTokenSource(); + using var response = await _httpClient.GetAsync(CurrentUpdateInfo.DownloadAddress, HttpCompletionOption.ResponseHeadersRead, _getUpdateInfoCancelToken.Token); + var buffer = new byte[_bufferLength]; + var totalBytes = response.Content.Headers.ContentLength ?? 0; + var readBytes = 0L; - return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null); - } - - private void GetUpdateInfo() - { - var e = DownloadString(UpdateChannelInfo.GetUpdateChannelInfo()); - - if (!e.Cancelled && e.Error == null) - { - try + await using (var httpStream = await response.Content.ReadAsStreamAsync(_getUpdateInfoCancelToken.Token)) { - CurrentUpdateInfo = UpdateInfo.FromString(e.Result); + await using var fileStream = new FileStream(CurrentUpdateInfo.UpdateFilePath, FileMode.Create, + FileAccess.Write, FileShare.None, _bufferLength, true); - Settings.Default.CheckForUpdatesLastCheck = DateTime.UtcNow; - if (!Settings.Default.UpdatePending) + while (readBytes <= totalBytes || !_getUpdateInfoCancelToken.IsCancellationRequested) { - Settings.Default.UpdatePending = IsUpdateAvailable(); + var bytesRead = + await httpStream.ReadAsync(buffer, 0, _bufferLength, _getUpdateInfoCancelToken.Token); + if (bytesRead == 0) + { + progress.Report(100); + break; + } + + await fileStream.WriteAsync(buffer, 0, bytesRead, _getUpdateInfoCancelToken.Token); + + readBytes += bytesRead; + + var percentComplete = (int)(readBytes * 100 / totalBytes); + progress.Report(percentComplete); } } - catch (Exception ex) - { - e = NewDownloadStringCompletedEventArgs(e.Result, ex, e.Cancelled, null); - } - } - GetUpdateInfoCompletedEventEvent?.Invoke(this, e); - } - - private void GetChangeLog() - { - var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress); - - if (!e.Cancelled && e.Error == null) - { - ChangeLog = e.Result; - } - - GetChangeLogCompletedEventEvent?.Invoke(this, e); - } - - private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - DownloadUpdateProgressChangedEventEvent?.Invoke(sender, e); - } - - private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) - { - var raiseEventArgs = e; - - if (!e.Cancelled && e.Error == null) - { - try - { #if !PORTABLE var updateAuthenticode = new Authenticode(CurrentUpdateInfo.UpdateFilePath) { @@ -307,101 +182,85 @@ namespace mRemoteNG.App.Update } #endif - using (var cksum = SHA512.Create()) - { - using (var stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath)) - { - var hash = cksum.ComputeHash(stream); - var hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant(); - if (!hashString.Equals(CurrentUpdateInfo.Checksum)) - throw new Exception("SHA512 Hashes didn't match!"); - } - } - } - catch (Exception ex) - { - raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null); - } + using var checksum = SHA512.Create(); + await using var stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath); + var hash = await checksum.ComputeHashAsync(stream); + var hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant(); + if (!hashString.Equals(CurrentUpdateInfo.Checksum)) + throw new Exception("SHA512 Hashes didn't match!"); + } finally{ + _getUpdateInfoCancelToken?.Dispose(); + _getUpdateInfoCancelToken = null; } - - if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null) - { - File.Delete(CurrentUpdateInfo.UpdateFilePath); - } - - DownloadUpdateCompletedEventEvent?.Invoke(this, raiseEventArgs); - - _downloadUpdateWebClient.Dispose(); - _downloadUpdateWebClient = null; } #endregion - #region Events + #region Private Methods - private AsyncCompletedEventHandler GetUpdateInfoCompletedEventEvent; - - public event AsyncCompletedEventHandler GetUpdateInfoCompletedEvent + private void UpdateHttpClient() { - add + if (_httpClient != null) { - GetUpdateInfoCompletedEventEvent = - (AsyncCompletedEventHandler)Delegate.Combine(GetUpdateInfoCompletedEventEvent, value); + _httpClient.Dispose(); } - remove + + var httpClientHandler = new HttpClientHandler(); + if (_webProxy != null) { - GetUpdateInfoCompletedEventEvent = - (AsyncCompletedEventHandler)Delegate.Remove(GetUpdateInfoCompletedEventEvent, value); + httpClientHandler.UseProxy = true; + httpClientHandler.Proxy = _webProxy; + } + _httpClient = new HttpClient(httpClientHandler); + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(GeneralAppInfo.UserAgent); + } + + public async Task GetUpdateInfoAsync() + { + if (IsGetUpdateInfoRunning) + { + _getUpdateInfoCancelToken.Cancel(); + _getUpdateInfoCancelToken.Dispose(); + _getUpdateInfoCancelToken = null; + } + + try + { + _getUpdateInfoCancelToken = new CancellationTokenSource(); + var updateInfo = await _httpClient.GetStringAsync(UpdateChannelInfo.GetUpdateChannelInfo(), _getUpdateInfoCancelToken.Token); + CurrentUpdateInfo = UpdateInfo.FromString(updateInfo); + Settings.Default.CheckForUpdatesLastCheck = DateTime.UtcNow; + + if (!Settings.Default.UpdatePending) + { + Settings.Default.UpdatePending = IsUpdateAvailable(); + } + } + finally + { + _getUpdateInfoCancelToken?.Dispose(); + _getUpdateInfoCancelToken = null; } } - private AsyncCompletedEventHandler GetChangeLogCompletedEventEvent; - - public event AsyncCompletedEventHandler GetChangeLogCompletedEvent + public async Task GetChangeLogAsync() { - add + if (IsGetChangeLogRunning) { - GetChangeLogCompletedEventEvent = - (AsyncCompletedEventHandler)Delegate.Combine(GetChangeLogCompletedEventEvent, value); + _changeLogCancelToken.Cancel(); + _changeLogCancelToken.Dispose(); + _changeLogCancelToken = null; } - remove - { - GetChangeLogCompletedEventEvent = - (AsyncCompletedEventHandler)Delegate.Remove(GetChangeLogCompletedEventEvent, value); - } - } - private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent; - - public event DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEvent - { - add + try { - DownloadUpdateProgressChangedEventEvent = - (DownloadProgressChangedEventHandler)Delegate.Combine(DownloadUpdateProgressChangedEventEvent, - value); + _changeLogCancelToken = new CancellationTokenSource(); + return await _httpClient.GetStringAsync(CurrentUpdateInfo.ChangeLogAddress, _changeLogCancelToken.Token); } - remove + finally { - DownloadUpdateProgressChangedEventEvent = - (DownloadProgressChangedEventHandler)Delegate.Remove(DownloadUpdateProgressChangedEventEvent, - value); - } - } - - private AsyncCompletedEventHandler DownloadUpdateCompletedEventEvent; - - public event AsyncCompletedEventHandler DownloadUpdateCompletedEvent - { - add - { - DownloadUpdateCompletedEventEvent = - (AsyncCompletedEventHandler)Delegate.Combine(DownloadUpdateCompletedEventEvent, value); - } - remove - { - DownloadUpdateCompletedEventEvent = - (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value); + _changeLogCancelToken?.Dispose(); + _changeLogCancelToken = null; } } diff --git a/mRemoteNG/UI/Forms/OptionsPages/UpdatesPage.cs b/mRemoteNG/UI/Forms/OptionsPages/UpdatesPage.cs index 4e336e54..d269b31e 100644 --- a/mRemoteNG/UI/Forms/OptionsPages/UpdatesPage.cs +++ b/mRemoteNG/UI/Forms/OptionsPages/UpdatesPage.cs @@ -159,8 +159,6 @@ namespace mRemoteNG.UI.Forms.OptionsPages #endregion - #region Private Methods - #region Event Handlers private void chkCheckForUpdatesOnStartup_CheckedChanged(object sender, EventArgs e) @@ -194,7 +192,7 @@ namespace mRemoteNG.UI.Forms.OptionsPages } } - private void btnTestProxy_Click(object sender, EventArgs e) + private async void btnTestProxy_Click(object sender, EventArgs e) { if (_appUpdate != null) { @@ -210,13 +208,27 @@ namespace mRemoteNG.UI.Forms.OptionsPages (int)numProxyPort.Value, chkUseProxyAuthentication.Checked, txtProxyUsername.Text, txtProxyPassword.Text); + try + { + btnTestProxy.Enabled = false; + btnTestProxy.Text = Language.OptionsProxyTesting; - btnTestProxy.Enabled = false; - btnTestProxy.Text = Language.OptionsProxyTesting; + await _appUpdate.GetUpdateInfoAsync(); - _appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted; + btnTestProxy.Enabled = true; + btnTestProxy.Text = Language.TestProxy; + CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.ProxyTestSucceeded, "", + Language._Ok, false); + } + catch (Exception ex) + { + CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.ProxyTestFailed, + MiscTools.GetExceptionMessageRecursive(ex), "", "", "", Language._Ok, + false, + ESysIcons.Error, + 0); + } - _appUpdate.GetUpdateInfoAsync(); } private void chkUseProxyAuthentication_CheckedChanged(object sender, EventArgs e) @@ -228,46 +240,5 @@ namespace mRemoteNG.UI.Forms.OptionsPages } #endregion - - private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e) - { - if (InvokeRequired) - { - AsyncCompletedEventHandler myDelegate = GetUpdateInfoCompleted; - Invoke(myDelegate, sender, e); - return; - } - - try - { - _appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted; - - btnTestProxy.Enabled = true; - btnTestProxy.Text = Language.TestProxy; - - if (e.Cancelled) - { - return; - } - - if (e.Error != null) - { - throw e.Error; - } - - CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.ProxyTestSucceeded, "", - Language._Ok, false); - } - catch (Exception ex) - { - CTaskDialog.ShowCommandBox(this, Application.ProductName, Language.ProxyTestFailed, - MiscTools.GetExceptionMessageRecursive(ex), "", "", "", Language._Ok, - false, - ESysIcons.Error, - 0); - } - } - - #endregion } } \ No newline at end of file diff --git a/mRemoteNG/UI/Forms/frmMain.cs b/mRemoteNG/UI/Forms/frmMain.cs index a05b7d7e..d8c25c3e 100644 --- a/mRemoteNG/UI/Forms/frmMain.cs +++ b/mRemoteNG/UI/Forms/frmMain.cs @@ -25,6 +25,7 @@ using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Text; +using System.Threading.Tasks; using System.Windows.Forms; using mRemoteNG.UI.Panels; using WeifenLuo.WinFormsUI.Docking; @@ -339,10 +340,10 @@ namespace mRemoteNG.UI.Forms } } - private void frmMain_Shown(object sender, EventArgs e) + private async void frmMain_Shown(object sender, EventArgs e) { PromptForUpdatesPreference(); - CheckForUpdates(); + await CheckForUpdates(); } private void PromptForUpdatesPreference() @@ -374,7 +375,7 @@ namespace mRemoteNG.UI.Forms } } - private void CheckForUpdates() + private async Task CheckForUpdates() { if (!Settings.Default.CheckForUpdatesOnStartup) return; @@ -385,7 +386,7 @@ namespace mRemoteNG.UI.Forms if (!IsHandleCreated) CreateHandle(); // Make sure the handle is created so that InvokeRequired returns the correct result - Startup.Instance.CheckForUpdate(); + await Startup.Instance.CheckForUpdate(); } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) diff --git a/mRemoteNG/UI/Window/UpdateWindow.cs b/mRemoteNG/UI/Window/UpdateWindow.cs index 0d0da221..e7d405c9 100644 --- a/mRemoteNG/UI/Window/UpdateWindow.cs +++ b/mRemoteNG/UI/Window/UpdateWindow.cs @@ -1,9 +1,7 @@ using System; -using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.IO; -using System.Net; using System.Windows.Forms; using mRemoteNG.App; using mRemoteNG.App.Update; @@ -11,13 +9,14 @@ using mRemoteNG.Messages; using mRemoteNG.Themes; using WeifenLuo.WinFormsUI.Docking; using mRemoteNG.Resources.Language; +using System.Threading.Tasks; namespace mRemoteNG.UI.Window { public partial class UpdateWindow : BaseWindow { private AppUpdater _appUpdate; - private bool _isUpdateDownloadHandlerDeclared; + //private bool _isUpdateDownloadHandlerDeclared; #region Public Methods @@ -38,12 +37,12 @@ namespace mRemoteNG.UI.Window #region Form Stuff - private void Update_Load(object sender, EventArgs e) + private async void Update_Load(object sender, EventArgs e) { ApplyTheme(); ThemeManager.getInstance().ThemeChanged += ApplyTheme; ApplyLanguage(); - CheckForUpdate(); + await CheckForUpdateAsync(); } private new void ApplyTheme() @@ -72,14 +71,14 @@ namespace mRemoteNG.UI.Window lblLatestVersionLabel.Text = $"{Language.AvailableVersion}:"; } - private void btnCheckForUpdate_Click(object sender, EventArgs e) + private async void btnCheckForUpdate_Click(object sender, EventArgs e) { - CheckForUpdate(); + await CheckForUpdateAsync(); } - private void btnDownload_Click(object sender, EventArgs e) + private async void btnDownload_Click(object sender, EventArgs e) { - DownloadUpdate(); + await DownloadUpdateAsync(); } private void pbUpdateImage_Click(object sender, EventArgs e) @@ -97,7 +96,7 @@ namespace mRemoteNG.UI.Window #region Private Methods - private void CheckForUpdate() + private async Task CheckForUpdateAsync() { if (_appUpdate == null) { @@ -119,39 +118,15 @@ namespace mRemoteNG.UI.Window SetVisibilityOfUpdateControls(false); - _appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted; - - _appUpdate.GetUpdateInfoAsync(); - } - - private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e) - { - if (InvokeRequired) - { - var myDelegate = new AsyncCompletedEventHandler(GetUpdateInfoCompleted); - Invoke(myDelegate, sender, e); - return; - } - try { - _appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted; + await _appUpdate.GetUpdateInfoAsync(); lblInstalledVersion.Text = Application.ProductVersion; lblInstalledVersion.Visible = true; lblInstalledVersionLabel.Visible = true; btnCheckForUpdate.Visible = true; - if (e.Cancelled) - { - return; - } - - if (e.Error != null) - { - throw e.Error; - } - if (_appUpdate.IsUpdateAvailable()) { lblStatus.Text = Language.UpdateAvailable; @@ -174,8 +149,15 @@ namespace mRemoteNG.UI.Window pbUpdateImage.Visible = true; } - _appUpdate.GetChangeLogCompletedEvent += GetChangeLogCompleted; - _appUpdate.GetChangeLogAsync(); + try + { + var changeLog = await _appUpdate.GetChangeLogAsync(); + txtChangeLog.Text = changeLog.Replace("\n", Environment.NewLine); + } + catch (Exception ex) + { + Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateGetChangeLogFailed, ex); + } btnDownload.Focus(); } @@ -200,7 +182,7 @@ namespace mRemoteNG.UI.Window Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateCheckCompleteFailed, ex); } } - + private void SetVisibilityOfUpdateControls(bool visible) { lblChangeLogLabel.Visible = visible; @@ -209,33 +191,7 @@ namespace mRemoteNG.UI.Window prgbDownload.Visible = visible; } - private void GetChangeLogCompleted(object sender, AsyncCompletedEventArgs e) - { - if (InvokeRequired) - { - var myDelegate = new AsyncCompletedEventHandler(GetChangeLogCompleted); - Invoke(myDelegate, sender, e); - return; - } - - try - { - _appUpdate.GetChangeLogCompletedEvent -= GetChangeLogCompleted; - - if (e.Cancelled) - return; - if (e.Error != null) - throw e.Error; - - txtChangeLog.Text = _appUpdate.ChangeLog.Replace("\n", Environment.NewLine); - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateGetChangeLogFailed, ex); - } - } - - private void DownloadUpdate() + private async Task DownloadUpdateAsync() { try { @@ -243,49 +199,18 @@ namespace mRemoteNG.UI.Window prgbDownload.Visible = true; prgbDownload.Value = 0; - if (_isUpdateDownloadHandlerDeclared == false) - { - _appUpdate.DownloadUpdateProgressChangedEvent += DownloadUpdateProgressChanged; - _appUpdate.DownloadUpdateCompletedEvent += DownloadUpdateCompleted; - _isUpdateDownloadHandlerDeclared = true; - } + await _appUpdate.DownloadUpdateAsync(new Progress(progress => prgbDownload.Value = progress)); - _appUpdate.DownloadUpdateAsync(); - } - catch (Exception ex) - { - Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateDownloadFailed, ex); - } - } - - #endregion - - #region Events - - private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e) - { - prgbDownload.Value = e.ProgressPercentage; - } - - private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e) - { - try - { btnDownload.Enabled = true; prgbDownload.Visible = false; - if (e.Cancelled) - return; - if (e.Error != null) - throw e.Error; - if (Runtime.IsPortableEdition) MessageBox.Show(Language.UpdatePortableDownloadComplete, Language.CheckForUpdates, - MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBoxButtons.OK, MessageBoxIcon.Information); else { if (MessageBox.Show(Language.UpdateDownloadComplete, Language.CheckForUpdates, - MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) + MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) { Shutdown.Quit(_appUpdate.CurrentUpdateInfo.UpdateFilePath); } @@ -297,8 +222,11 @@ namespace mRemoteNG.UI.Window } catch (Exception ex) { + Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateDownloadFailed, ex); + Runtime.MessageCollector?.AddExceptionStackTrace(Language.UpdateDownloadCompleteFailed, ex); Runtime.MessageCollector?.AddMessage(MessageClass.ErrorMsg, ex.Message); + } }