From 38485e1c86b0cde8b9f56e547b3c678664c9dac0 Mon Sep 17 00:00:00 2001 From: Yair <39923744+yaira2@users.noreply.github.com> Date: Wed, 19 Nov 2025 14:40:07 -0500 Subject: [PATCH 1/2] Code Quality: Refactor launcher update logic and remove hash check Removed SHA256 hash file and related hash comparison logic from Files.App.Launcher update process. Now uses a branch file (Branch.txt) to determine if the launcher should be updated, simplifying the update mechanism. Updated PowerShell command to ensure Branch.txt is created during setup. This streamlines the update process and improves maintainability. --- .../Files.App.Launcher.vcxproj | 3 +- .../Files.App.Launcher.exe.sha256 | 1 - .../Helpers/Application/AppLifecycleHelper.cs | 4 +- .../Services/App/AppUpdateSideloadService.cs | 46 +++++------------- .../Services/App/AppUpdateStoreService.cs | 47 ++++++------------- .../ViewModels/Settings/AdvancedViewModel.cs | 2 +- 6 files changed, 33 insertions(+), 70 deletions(-) delete mode 100644 src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 diff --git a/src/Files.App.Launcher/Files.App.Launcher.vcxproj b/src/Files.App.Launcher/Files.App.Launcher.vcxproj index 1b7ac20e96db..c9fbaf6c3f91 100644 --- a/src/Files.App.Launcher/Files.App.Launcher.vcxproj +++ b/src/Files.App.Launcher/Files.App.Launcher.vcxproj @@ -66,8 +66,7 @@ - xcopy /s /y "$(ProjectDir)$(OutDir)*.exe" "$(ProjectDir)..\..\src\Files.App\Assets\FilesOpenDialog" - certutil -hashfile "$(ProjectDir)..\..\src\Files.App\Assets\FilesOpenDialog\$(TargetFileName)" SHA256|findstr /R /V "^SHA256 ^CertUtil">"$(ProjectDir)..\..\src\Files.App\Assets\FilesOpenDialog\$(TargetFileName).sha256" + xcopy /s /y "$(ProjectDir)$(OutDir)*.exe" "$(ProjectDir)..\..\src\Files.App\Assets\FilesOpenDialog" diff --git a/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 b/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 deleted file mode 100644 index 11864831640e..000000000000 --- a/src/Files.App/Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256 +++ /dev/null @@ -1 +0,0 @@ -cb1ca000ef2f03f1afc7bde9ed4fb2987669c89a58b63919e67574696091f60f diff --git a/src/Files.App/Helpers/Application/AppLifecycleHelper.cs b/src/Files.App/Helpers/Application/AppLifecycleHelper.cs index 9998ab269836..ecbb8edc5f52 100644 --- a/src/Files.App/Helpers/Application/AppLifecycleHelper.cs +++ b/src/Files.App/Helpers/Application/AppLifecycleHelper.cs @@ -169,7 +169,9 @@ await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () => await updateService.CheckForUpdatesAsync(); await updateService.DownloadMandatoryUpdatesAsync(); - await updateService.CheckAndUpdateFilesLauncherAsync(); + + if (IsAppUpdated) + await updateService.CheckAndUpdateFilesLauncherAsync(); } /// diff --git a/src/Files.App/Services/App/AppUpdateSideloadService.cs b/src/Files.App/Services/App/AppUpdateSideloadService.cs index e49c8dcf79d9..f1fc9c812ad9 100644 --- a/src/Files.App/Services/App/AppUpdateSideloadService.cs +++ b/src/Files.App/Services/App/AppUpdateSideloadService.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging; using System.IO; using System.Net.Http; +using System.Text; using System.Xml.Serialization; using Windows.ApplicationModel; using Windows.Management.Deployment; @@ -125,52 +126,31 @@ public async Task CheckAndUpdateFilesLauncherAsync() { var destFolderPath = Path.Combine(UserDataPaths.GetDefault().LocalAppData, "Files"); var destExeFilePath = Path.Combine(destFolderPath, "Files.App.Launcher.exe"); + var branchFilePath = Path.Combine(destFolderPath, "Branch.txt"); + // If Files.App.Launcher.exe doesn't exist, no need to update it. if (!File.Exists(destExeFilePath)) return; - var hashEqual = false; - var srcHashFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256")) - .AsTask().ConfigureAwait(false); - var destHashFilePath = Path.Combine(destFolderPath, "Files.App.Launcher.exe.sha256"); - - if (File.Exists(destHashFilePath)) - { - await using var srcStream = (await srcHashFile.OpenReadAsync().AsTask().ConfigureAwait(false)).AsStream(); - await using var destStream = File.OpenRead(destHashFilePath); - hashEqual = HashEqual(srcStream, destStream); - } + // Check if the launcher file is associated with the current branch of the app. Users updating from versions earlier than + // v4.0.20 will not have the branch file in which case we create it for them. + if (File.Exists(branchFilePath) && await File.ReadAllTextAsync(branchFilePath, Encoding.UTF8) != "files-dev") + return; + else if (!File.Exists(branchFilePath)) + await File.WriteAllTextAsync(branchFilePath, "files-dev", Encoding.UTF8); - if (!hashEqual) - { - var srcExeFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe")) - .AsTask().ConfigureAwait(false); - var destFolder = await StorageFolder.GetFolderFromPathAsync(destFolderPath).AsTask().ConfigureAwait(false); + var srcExeFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe")); + var destFolder = await StorageFolder.GetFolderFromPathAsync(destFolderPath); - await srcExeFile.CopyAsync(destFolder, "Files.App.Launcher.exe", NameCollisionOption.ReplaceExisting) - .AsTask().ConfigureAwait(false); - await srcHashFile.CopyAsync(destFolder, "Files.App.Launcher.exe.sha256", NameCollisionOption.ReplaceExisting) - .AsTask().ConfigureAwait(false); + await srcExeFile.CopyAsync(destFolder, "Files.App.Launcher.exe", NameCollisionOption.ReplaceExisting); - Logger?.LogInformation("Files.App.Launcher updated."); - } + App.Logger.LogInformation("Files.App.Launcher updated."); } catch (Exception ex) { Logger?.LogError(ex, ex.Message); return; } - - bool HashEqual(Stream a, Stream b) - { - Span bufferA = stackalloc byte[64]; - Span bufferB = stackalloc byte[64]; - - a.Read(bufferA); - b.Read(bufferB); - - return bufferA.SequenceEqual(bufferB); - } } public async Task CheckForReleaseNotesAsync() diff --git a/src/Files.App/Services/App/AppUpdateStoreService.cs b/src/Files.App/Services/App/AppUpdateStoreService.cs index 4d01a85c0da0..8e35dea69fe5 100644 --- a/src/Files.App/Services/App/AppUpdateStoreService.cs +++ b/src/Files.App/Services/App/AppUpdateStoreService.cs @@ -5,6 +5,7 @@ using Microsoft.UI.Xaml.Controls; using System.IO; using System.Net.Http; +using System.Text; using Windows.Foundation.Metadata; using Windows.Services.Store; using Windows.Storage; @@ -180,43 +181,25 @@ public async Task CheckAndUpdateFilesLauncherAsync() { var destFolderPath = Path.Combine(UserDataPaths.GetDefault().LocalAppData, "Files"); var destExeFilePath = Path.Combine(destFolderPath, "Files.App.Launcher.exe"); + var branchFilePath = Path.Combine(destFolderPath, "Branch.txt"); - if (Path.Exists(destExeFilePath)) - { - var hashEqual = false; - var srcHashFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe.sha256")); - var destHashFilePath = Path.Combine(destFolderPath, "Files.App.Launcher.exe.sha256"); - - if (Path.Exists(destHashFilePath)) - { - await using var srcStream = (await srcHashFile.OpenReadAsync()).AsStream(); - await using var destStream = File.OpenRead(destHashFilePath); - - hashEqual = HashEqual(srcStream, destStream); - } - - if (!hashEqual) - { - var srcExeFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe")); - var destFolder = await StorageFolder.GetFolderFromPathAsync(destFolderPath); - - await srcExeFile.CopyAsync(destFolder, "Files.App.Launcher.exe", NameCollisionOption.ReplaceExisting); - await srcHashFile.CopyAsync(destFolder, "Files.App.Launcher.exe.sha256", NameCollisionOption.ReplaceExisting); + // If Files.App.Launcher.exe doesn't exist, no need to update it. + if (!File.Exists(destExeFilePath)) + return; - App.Logger.LogInformation("Files.App.Launcher updated."); - } - } + // Check if the launcher file is associated with the current branch of the app. Users updating from versions earlier than + // v4.0.20 will not have the branch file in which case we create it for them. + if (File.Exists(branchFilePath) && await File.ReadAllTextAsync(branchFilePath, Encoding.UTF8) != "files-dev") + return; + else if (!File.Exists(branchFilePath)) + await File.WriteAllTextAsync(branchFilePath, "files-dev", Encoding.UTF8); - bool HashEqual(Stream a, Stream b) - { - Span bufferA = stackalloc byte[64]; - Span bufferB = stackalloc byte[64]; + var srcExeFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe")); + var destFolder = await StorageFolder.GetFolderFromPathAsync(destFolderPath); - a.Read(bufferA); - b.Read(bufferB); + await srcExeFile.CopyAsync(destFolder, "Files.App.Launcher.exe", NameCollisionOption.ReplaceExisting); - return bufferA.SequenceEqual(bufferB); - } + App.Logger.LogInformation("Files.App.Launcher updated."); } private bool HasUpdates() diff --git a/src/Files.App/ViewModels/Settings/AdvancedViewModel.cs b/src/Files.App/ViewModels/Settings/AdvancedViewModel.cs index 32816dd79508..805035588f1a 100644 --- a/src/Files.App/ViewModels/Settings/AdvancedViewModel.cs +++ b/src/Files.App/ViewModels/Settings/AdvancedViewModel.cs @@ -68,7 +68,7 @@ private async Task SetAsDefaultExplorerAsync() var dataPath = Environment.ExpandEnvironmentVariables("%LocalAppData%\\Files"); if (IsSetAsDefaultFileManager) { - if (!await Win32Helper.RunPowershellCommandAsync($"-command \"New-Item -Force -Path '{dataPath}' -ItemType Directory; Copy-Item -Filter *.* -Path '{destFolder}\\*' -Recurse -Force -Destination '{dataPath}'\"", PowerShellExecutionOptions.Hidden)) + if (!await Win32Helper.RunPowershellCommandAsync($"-command \"New-Item -Force -Path '{dataPath}' -ItemType Directory; Copy-Item -Filter *.* -Path '{destFolder}\\*' -Recurse -Force -Destination '{dataPath}'; 'files-dev' | Out-File -Encoding utf8 -Force -FilePath '{dataPath}\\Branch.txt'\"", PowerShellExecutionOptions.Hidden)) { // Error copying files await DetectResult(); From 2785b592b4f9a73bdcddf2ab017f1c0ab7ae0a7d Mon Sep 17 00:00:00 2001 From: Yair <39923744+yaira2@users.noreply.github.com> Date: Wed, 19 Nov 2025 15:01:31 -0500 Subject: [PATCH 2/2] Try catch --- .../Services/App/AppUpdateSideloadService.cs | 26 ++++++++++++++----- .../Services/App/AppUpdateStoreService.cs | 26 ++++++++++++++----- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/Files.App/Services/App/AppUpdateSideloadService.cs b/src/Files.App/Services/App/AppUpdateSideloadService.cs index f1fc9c812ad9..b79cb44016f4 100644 --- a/src/Files.App/Services/App/AppUpdateSideloadService.cs +++ b/src/Files.App/Services/App/AppUpdateSideloadService.cs @@ -132,12 +132,26 @@ public async Task CheckAndUpdateFilesLauncherAsync() if (!File.Exists(destExeFilePath)) return; - // Check if the launcher file is associated with the current branch of the app. Users updating from versions earlier than - // v4.0.20 will not have the branch file in which case we create it for them. - if (File.Exists(branchFilePath) && await File.ReadAllTextAsync(branchFilePath, Encoding.UTF8) != "files-dev") - return; - else if (!File.Exists(branchFilePath)) - await File.WriteAllTextAsync(branchFilePath, "files-dev", Encoding.UTF8); + // Check if the launcher file is associated with the current branch of the app. + if (File.Exists(branchFilePath)) + { + try + { + var branch = await File.ReadAllTextAsync(branchFilePath, Encoding.UTF8); + if (!string.Equals(branch.Trim(), "files-dev", StringComparison.OrdinalIgnoreCase)) + return; + } + catch { } + } + else + { + try + { + // Create branch file for users updating from versions earlier than v4.0.20. + await File.WriteAllTextAsync(branchFilePath, "files-dev", Encoding.UTF8); + } + catch { } + } var srcExeFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe")); var destFolder = await StorageFolder.GetFolderFromPathAsync(destFolderPath); diff --git a/src/Files.App/Services/App/AppUpdateStoreService.cs b/src/Files.App/Services/App/AppUpdateStoreService.cs index 8e35dea69fe5..b259937d681f 100644 --- a/src/Files.App/Services/App/AppUpdateStoreService.cs +++ b/src/Files.App/Services/App/AppUpdateStoreService.cs @@ -187,12 +187,26 @@ public async Task CheckAndUpdateFilesLauncherAsync() if (!File.Exists(destExeFilePath)) return; - // Check if the launcher file is associated with the current branch of the app. Users updating from versions earlier than - // v4.0.20 will not have the branch file in which case we create it for them. - if (File.Exists(branchFilePath) && await File.ReadAllTextAsync(branchFilePath, Encoding.UTF8) != "files-dev") - return; - else if (!File.Exists(branchFilePath)) - await File.WriteAllTextAsync(branchFilePath, "files-dev", Encoding.UTF8); + // Check if the launcher file is associated with the current branch of the app. + if (File.Exists(branchFilePath)) + { + try + { + var branch = await File.ReadAllTextAsync(branchFilePath, Encoding.UTF8); + if (!string.Equals(branch.Trim(), "files-dev", StringComparison.OrdinalIgnoreCase)) + return; + } + catch { } + } + else + { + try + { + // Create branch file for users updating from versions earlier than v4.0.20. + await File.WriteAllTextAsync(branchFilePath, "files-dev", Encoding.UTF8); + } + catch { } + } var srcExeFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FilesOpenDialog/Files.App.Launcher.exe")); var destFolder = await StorageFolder.GetFolderFromPathAsync(destFolderPath);