Skip to content

Commit

Permalink
Execute update in separate thread
Browse files Browse the repository at this point in the history
* Use a task to run the update process
* Disable TopMost and just Focus the main window on launch
* Wait for in-use files to be closed and prompt user
  • Loading branch information
rex706 committed Jun 28, 2023
1 parent b0c31eb commit b955522
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 73 deletions.
16 changes: 10 additions & 6 deletions Updater/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Updater"
mc:Ignorable="d"
Title="Updater" Height="250" Width="346" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen" Background="#FF333638" Icon="unnamed.ico" Topmost="True">
Title="Updater" Height="250" Width="400" ResizeMode="CanMinimize" WindowStartupLocation="CenterScreen" Background="#FF333638" Icon="unnamed.ico">
<Grid>
<ProgressBar x:Name="progressBar" Height="23" Margin="10,10,10,0" VerticalAlignment="Top"/>
<Label x:Name="labelSpeed" Content="0 kb/s" HorizontalAlignment="Center" Margin="10,38,174,159" HorizontalContentAlignment="Center" Width="156" Foreground="White" Height="24" VerticalAlignment="Center"/>
<Label x:Name="labelPerc" Content="" Margin="10,10,10,0" VerticalAlignment="Top" HorizontalContentAlignment="Center" Height="23" />
<Label x:Name="labelDownloaded" Content="0 b" HorizontalAlignment="Center" Margin="171,38,10,159" HorizontalContentAlignment="Center" Width="159" Foreground="White" Height="24" VerticalAlignment="Center"/>
<TextBox x:Name="ConsoleBox" IsReadOnly="True" TextWrapping="Wrap" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True" Background="#FF191919" Foreground="#FFF1F1F1" Height="144" Margin="10,0,10,10" Text="" VerticalAlignment="Bottom"/>
<Grid Margin="0,0,0,117">
<ProgressBar x:Name="progressBar" Height="23" Margin="10,10,10,0" VerticalAlignment="Top"/>
<Label x:Name="labelSpeed" Content="0 kb/s" Margin="10,38,200,1" HorizontalContentAlignment="Center" Foreground="White"/>
<Label x:Name="labelDownloaded" Content="0 b" Margin="200,38,10,1" HorizontalContentAlignment="Center" Foreground="White"/>
<Label x:Name="labelPerc" Content="" Margin="10,10,10,0" VerticalAlignment="Top" HorizontalContentAlignment="Center" Height="23" />
</Grid>
<Grid Margin="0,59,0,0">
<TextBox x:Name="ConsoleBox" IsReadOnly="True" TextWrapping="Wrap" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Auto" Background="#FF191919" Foreground="#FFF1F1F1" Text="" Margin="10,10,10,10" TextChanged="ConsoleBox_TextChanged"/>
</Grid>
</Grid>
</Window>
210 changes: 143 additions & 67 deletions Updater/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Updater
{
Expand All @@ -26,6 +28,8 @@ public partial class MainWindow : Window
{
private WebClient webClient; // Our WebClient that will be doing the downloading for us.
private Stopwatch sw = new Stopwatch(); // The stopwatch which we will be using to calculate the download speed.
private readonly int sleep = 1000;
private readonly int maxSleep = 10000;

public MainWindow()
{
Expand All @@ -44,7 +48,9 @@ private async void MainWindow_LoadedAsync(object sender, RoutedEventArgs e)

string manifestUrl = null;

foreach(string arg in args)
Focus();

foreach (string arg in args)
{
if (Uri.TryCreate(arg, UriKind.Absolute, out _) && !File.Exists(arg))
{
Expand All @@ -60,79 +66,96 @@ private async void MainWindow_LoadedAsync(object sender, RoutedEventArgs e)
return;
}

ConsoleBox.AppendText("Reading update manifest . . .\n");
ConsoleBox.AppendText("Reading update manifest . . .\n" + manifestUrl + "\n");

List<Download> downloads = new List<Download>();

// Open the text file using a stream reader.
using (WebClient client = new WebClient())
try
{
// Open the text file using a stream reader.
using (Stream stream = await client.OpenReadTaskAsync(manifestUrl))
using (WebClient client = new WebClient())
{
StreamReader reader = new StreamReader(stream);

// Initialize variables.
Version latest = null;
string executable = null;

try
{
// First two expected items in manifest will be the new version and the starting executable.
string v = await reader.ReadLineAsync();
latest = Version.Parse(v);
executable = await reader.ReadLineAsync();
}
catch (Exception m)
{
MessageBox.Show("Error parsing new version number or launch executable.\n\n" + m.Message + "\n\nManifest: " + manifestUrl);
Close();
return;
}

// Load manifest urls and file names.
while (!reader.EndOfStream)
// Open the text file using a stream reader.
using (Stream stream = await client.OpenReadTaskAsync(manifestUrl))
{
try
{
// Expected in pairs of two.
string downloadUrl = await reader.ReadLineAsync();
string downloadFile = await reader.ReadLineAsync();
StreamReader reader = new StreamReader(stream);

// Initialize variables.
Version latest = null;
string executable = null;

if (downloadUrl == null || downloadFile == null)
try
{
// First two expected items in manifest will be the new version and the starting executable.
string v = await reader.ReadLineAsync();
latest = Version.Parse(v);
executable = await reader.ReadLineAsync();
}
catch (Exception m)
{
MessageBox.Show("Uneven update manifest.\nPlease review format.");
MessageBox.Show("Error parsing new version number or launch executable.\n\n" + m.Message + "\n\nManifest: " + manifestUrl);
Close();
return;
}

// If a new version of the updater is being acquired, rename it to be handled in UpdateCheck.cs
if (downloadFile == "Updater.exe")
// Load manifest urls and file names.
while (!reader.EndOfStream)
{
downloads.Add(new Download { url = downloadUrl, file = "Updater_new.exe" });
try
{
// Expected in pairs of two.
string downloadUrl = await reader.ReadLineAsync();
string downloadFile = await reader.ReadLineAsync();

if (downloadUrl == null || downloadFile == null)
{
MessageBox.Show("Uneven update manifest.\nPlease review format.");
Close();
return;
}

// If a new version of the updater is being acquired, rename it to be handled in UpdateCheck.cs
if (downloadFile == "Updater.exe")
{
downloads.Add(new Download { url = downloadUrl, file = "Updater_new.exe" });
}
else
{
downloads.Add(new Download { url = downloadUrl, file = downloadFile });
}
}
catch (Exception m)
{
MessageBox.Show("Uneven update manifest.\nPlease review format.");
Close();
return;
}
}
else
if (downloads.Count == 0)
{
downloads.Add(new Download { url = downloadUrl, file = downloadFile });
MessageBox.Show("No download arguments found in manifest.");
Close();
return;
}

ConsoleBox.AppendText("Starting update sequence . . .\n");
Task.Run(() => Update(executable, downloads));
}
catch (Exception m)
catch (Exception ex)
{
MessageBox.Show("Uneven update manifest.\nPlease review format.");
MessageBox.Show("Error initilaizing stream reader for update manifest\n\n" + ex.Message);
Close();
return;
}
}
if (downloads.Count == 0)
{
MessageBox.Show("No download arguments found in manifest.");
Close();
return;
}

Update(executable, downloads);
}
}
catch (Exception ex)
{
MessageBox.Show("Error reading the update manifest\n\n" + manifestUrl + "\n\n" + ex.Message);
Close();
}
}

private async void Update(string executable, List<Download> downloads)
Expand All @@ -143,26 +166,33 @@ private async void Update(string executable, List<Download> downloads)
await DownloadFile(download.url, download.file);
}

ConsoleBox.AppendText("Update complete!\n");
Dispatcher.Invoke(() => { ConsoleBox.AppendText("Update complete!\n"); });
//MessageBox.Show("Update complete!");

// First argument is the program to be opened when the update is complete.
if (executable != null && executable.Length > 1 && executable.Contains(".exe"))
{
ConsoleBox.AppendText("Attempting to start" + executable + " . . .\n");
Dispatcher.Invoke(() => { ConsoleBox.AppendText("Attempting to start '" + executable + "' . . .\n"); });

ProcessStartInfo info = new ProcessStartInfo();
info.UseShellExecute = true;
info.FileName = executable;

try
{
Process.Start(executable);
Process.Start(info);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}

// Close updater.
Close();

Dispatcher.Invoke(() => { ConsoleBox.AppendText("Closing updater . . . \n"); });

Thread.Sleep(sleep);

Dispatcher.Invoke(() => { Close(); });
}

public async Task DownloadFile(string urlAddress, string fileName)
Expand All @@ -174,21 +204,41 @@ public async Task DownloadFile(string urlAddress, string fileName)

string path = AppDomain.CurrentDomain.BaseDirectory + fileName;

// Delete files to update.
if (File.Exists(path))
try
{
File.Delete(path);
}
// Delete files to update.
if (File.Exists(path))
{
int totalSleep = 0;

// The variable that will be holding the url address (making sure it starts with http://).
Uri URL = new Uri(urlAddress);
while (IsFileLocked(path))
{
if (totalSleep > maxSleep)
{
MessageBox.Show("Please close " + fileName + " and click OK");
}

// Start the stopwatch which will be used to calculate the download speed.
sw.Start();
ConsoleBox.AppendText("Downloading '" + fileName + "' . . .\n");
Thread.Sleep(sleep);

Dispatcher.Invoke(() => { ConsoleBox.AppendText("Waiting for " + fileName + " to close . . .\n"); });

totalSleep += sleep;
}

File.Delete(path);
}

// The variable that will be holding the url address (making sure it starts with http://).
Uri URL = new Uri(urlAddress);

// Start the stopwatch which will be used to calculate the download speed.
sw.Start();

Dispatcher.Invoke(() =>
{
ConsoleBox.AppendText("Downloading '" + fileName + "' . . .\n");
});

try
{
// Start downloading the file.
await webClient.DownloadFileTaskAsync(URL, path);
}
Expand Down Expand Up @@ -230,9 +280,35 @@ private void Completed(object sender, AsyncCompletedEventArgs e)

if (e.Cancelled == true)
{
ConsoleBox.AppendText("Download has been cancelled.\n");
MessageBox.Show("Download has been canceled.");
Dispatcher.Invoke(() => { ConsoleBox.AppendText("Download has been cancelled.\n"); });
}
}

protected virtual bool IsFileLocked(string filePath)
{
try
{
using (FileStream stream = new FileStream(filePath, FileMode.Open))
{
stream.Close();
}
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}

//file is not locked
return false;
}

private void ConsoleBox_TextChanged(object sender, TextChangedEventArgs e)
{
ConsoleBox.ScrollToEnd();
}
}
}

0 comments on commit b955522

Please sign in to comment.