From 41556c84dd5820d82a1216d1a73f5eee2604d109 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Thu, 8 Dec 2022 00:04:26 +0100 Subject: [PATCH] Fix: Fix duplicate window opening when pressing Ctrl+N (#10648) --- src/Files.App/Helpers/NavigationHelpers.cs | 4 +-- src/Files.App/Helpers/UniversalLogWriter.cs | 30 ++++++++++++++++--- src/Files.App/ViewModels/MainPageViewModel.cs | 12 ++++---- src/Files.App/ViewModels/ToolbarViewModel.cs | 2 +- src/Files.App/Views/ColumnShellPage.xaml.cs | 2 +- src/Files.App/Views/ModernShellPage.xaml.cs | 2 +- src/Files.Shared/Logger.cs | 14 --------- 7 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/Files.App/Helpers/NavigationHelpers.cs b/src/Files.App/Helpers/NavigationHelpers.cs index e9396f9dd995..81b47f83e117 100644 --- a/src/Files.App/Helpers/NavigationHelpers.cs +++ b/src/Files.App/Helpers/NavigationHelpers.cs @@ -36,10 +36,10 @@ public static Task OpenTabInNewWindowAsync(string tabArgs) return Launcher.LaunchUriAsync(folderUri).AsTask(); } - public static async void LaunchNewWindow() + public static Task LaunchNewWindowAsync() { var filesUWPUri = new Uri("files-uwp:"); - await Launcher.LaunchUriAsync(filesUWPUri); + return Launcher.LaunchUriAsync(filesUWPUri).AsTask(); } public static async Task OpenSelectedItems(IShellPage associatedInstance, bool openViaApplicationPicker = false) diff --git a/src/Files.App/Helpers/UniversalLogWriter.cs b/src/Files.App/Helpers/UniversalLogWriter.cs index 669541b9ee00..7aeb5d259a2c 100644 --- a/src/Files.App/Helpers/UniversalLogWriter.cs +++ b/src/Files.App/Helpers/UniversalLogWriter.cs @@ -28,7 +28,9 @@ public async Task InitializeAsync(string name) if (logsBeforeInit.Count > 0) { - using var stream = await logFile.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders); + using var stream = await OpenFileWithRetryAsync(logFile, FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders); + if (stream is null) + return; using var outputStream = stream.GetOutputStreamAt(stream.Size); using var dataWriter = new DataWriter(outputStream); while (logsBeforeInit.TryDequeue(out var text)) @@ -48,7 +50,9 @@ public async Task WriteLineToLogAsync(string text) logsBeforeInit.Enqueue(text); return; } - using var stream = await logFile.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders); + using var stream = await OpenFileWithRetryAsync(logFile, FileAccessMode.ReadWrite, StorageOpenOptions.AllowOnlyReaders); + if (stream is null) + return; using var outputStream = stream.GetOutputStreamAt(stream.Size); using var dataWriter = new DataWriter(outputStream); dataWriter.WriteString("\n" + text); @@ -68,9 +72,7 @@ public void WriteLineToLog(string text) IntPtr hStream = CreateFileFromApp(logFile.Path, GENERIC_WRITE, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, (uint)File_Attributes.BackupSemantics, IntPtr.Zero); if (hStream.ToInt64() == -1) - { return; - } byte[] buff = Encoding.UTF8.GetBytes("\n" + text); int dwBytesWritten; unsafe @@ -85,5 +87,25 @@ public void WriteLineToLog(string text) Debug.WriteLine($"Logged event: {text}"); } + + private async Task OpenFileWithRetryAsync(IStorageFile2 file, FileAccessMode mode, StorageOpenOptions share, int maxRetries = 5) + { + for (int numTries = 0; numTries < maxRetries; numTries++) + { + IRandomAccessStream? fs = null; + try + { + fs = await file.OpenAsync(mode, share); + return fs; + } + catch (System.IO.IOException) + { + fs?.Dispose(); + await Task.Delay(50); + } + } + + return null; + } } } \ No newline at end of file diff --git a/src/Files.App/ViewModels/MainPageViewModel.cs b/src/Files.App/ViewModels/MainPageViewModel.cs index 0320f3e98cbc..1480058696b5 100644 --- a/src/Files.App/ViewModels/MainPageViewModel.cs +++ b/src/Files.App/ViewModels/MainPageViewModel.cs @@ -51,11 +51,11 @@ public bool IsWindowCompactOverlay public ICommand NavigateToNumberedTabKeyboardAcceleratorCommand { get; private set; } - public ICommand OpenNewWindowAcceleratorCommand { get; private set; } + public IAsyncRelayCommand OpenNewWindowAcceleratorCommand { get; private set; } public ICommand CloseSelectedTabKeyboardAcceleratorCommand { get; private set; } - public ICommand AddNewInstanceAcceleratorCommand { get; private set; } + public IAsyncRelayCommand AddNewInstanceAcceleratorCommand { get; private set; } public ICommand ReopenClosedTabAcceleratorCommand { get; private set; } @@ -65,9 +65,9 @@ public MainPageViewModel() { // Create commands NavigateToNumberedTabKeyboardAcceleratorCommand = new RelayCommand(NavigateToNumberedTabKeyboardAccelerator); - OpenNewWindowAcceleratorCommand = new RelayCommand(OpenNewWindowAccelerator); + OpenNewWindowAcceleratorCommand = new AsyncRelayCommand(OpenNewWindowAccelerator); CloseSelectedTabKeyboardAcceleratorCommand = new RelayCommand(CloseSelectedTabKeyboardAccelerator); - AddNewInstanceAcceleratorCommand = new RelayCommand(AddNewInstanceAccelerator); + AddNewInstanceAcceleratorCommand = new AsyncRelayCommand(AddNewInstanceAccelerator); ReopenClosedTabAcceleratorCommand = new RelayCommand(ReopenClosedTabAccelerator); OpenSettingsCommand = new RelayCommand(OpenSettings); } @@ -141,7 +141,7 @@ private void NavigateToNumberedTabKeyboardAccelerator(KeyboardAcceleratorInvoked e.Handled = true; } - private async void OpenNewWindowAccelerator(KeyboardAcceleratorInvokedEventArgs? e) + private async Task OpenNewWindowAccelerator(KeyboardAcceleratorInvokedEventArgs? e) { Uri filesUWPUri = new Uri("files-uwp:"); await Launcher.LaunchUriAsync(filesUWPUri); @@ -163,7 +163,7 @@ private void CloseSelectedTabKeyboardAccelerator(KeyboardAcceleratorInvokedEvent e!.Handled = true; } - private async void AddNewInstanceAccelerator(KeyboardAcceleratorInvokedEventArgs? e) + private async Task AddNewInstanceAccelerator(KeyboardAcceleratorInvokedEventArgs? e) { await AddNewTabAsync(); e!.Handled = true; diff --git a/src/Files.App/ViewModels/ToolbarViewModel.cs b/src/Files.App/ViewModels/ToolbarViewModel.cs index 5e612a1a6589..9b41bfde1565 100644 --- a/src/Files.App/ViewModels/ToolbarViewModel.cs +++ b/src/Files.App/ViewModels/ToolbarViewModel.cs @@ -781,7 +781,7 @@ public void SearchRegion_LostFocus(object sender, RoutedEventArgs e) public ICommand? PasteItemsFromClipboardCommand { get; set; } - public ICommand? OpenNewWindowCommand { get; set; } + public IAsyncRelayCommand? OpenNewWindowCommand { get; set; } public ICommand? OpenNewPaneCommand { get; set; } diff --git a/src/Files.App/Views/ColumnShellPage.xaml.cs b/src/Files.App/Views/ColumnShellPage.xaml.cs index b6a0d03d765f..0ecaca3ada72 100644 --- a/src/Files.App/Views/ColumnShellPage.xaml.cs +++ b/src/Files.App/Views/ColumnShellPage.xaml.cs @@ -270,7 +270,7 @@ private void InitToolbarCommands() ToolbarViewModel.InvertContentPageSelctionCommand = new RelayCommand(() => SlimContentPage?.ItemManipulationModel.InvertSelection()); ToolbarViewModel.ClearContentPageSelectionCommand = new RelayCommand(() => SlimContentPage?.ItemManipulationModel.ClearSelection()); ToolbarViewModel.PasteItemsFromClipboardCommand = new RelayCommand(async () => await UIFilesystemHelpers.PasteItemAsync(FilesystemViewModel.WorkingDirectory, this)); - ToolbarViewModel.OpenNewWindowCommand = new RelayCommand(NavigationHelpers.LaunchNewWindow); + ToolbarViewModel.OpenNewWindowCommand = new AsyncRelayCommand(NavigationHelpers.LaunchNewWindowAsync); ToolbarViewModel.OpenNewPaneCommand = new RelayCommand(() => PaneHolder?.OpenPathInNewPane("Home".GetLocalizedResource())); ToolbarViewModel.ClosePaneCommand = new RelayCommand(() => PaneHolder?.CloseActivePane()); ToolbarViewModel.CreateNewFileCommand = new RelayCommand(x => UIFilesystemHelpers.CreateFileFromDialogResultType(AddItemDialogItemType.File, x, this)); diff --git a/src/Files.App/Views/ModernShellPage.xaml.cs b/src/Files.App/Views/ModernShellPage.xaml.cs index d9160eb82432..af048f7030f0 100644 --- a/src/Files.App/Views/ModernShellPage.xaml.cs +++ b/src/Files.App/Views/ModernShellPage.xaml.cs @@ -239,7 +239,7 @@ private void InitToolbarCommands() ToolbarViewModel.InvertContentPageSelctionCommand = new RelayCommand(() => SlimContentPage?.ItemManipulationModel.InvertSelection()); ToolbarViewModel.ClearContentPageSelectionCommand = new RelayCommand(() => SlimContentPage?.ItemManipulationModel.ClearSelection()); ToolbarViewModel.PasteItemsFromClipboardCommand = new RelayCommand(async () => await UIFilesystemHelpers.PasteItemAsync(FilesystemViewModel.WorkingDirectory, this)); - ToolbarViewModel.OpenNewWindowCommand = new RelayCommand(NavigationHelpers.LaunchNewWindow); + ToolbarViewModel.OpenNewWindowCommand = new AsyncRelayCommand(NavigationHelpers.LaunchNewWindowAsync); ToolbarViewModel.OpenNewPaneCommand = new RelayCommand(() => PaneHolder?.OpenPathInNewPane("Home".GetLocalizedResource())); ToolbarViewModel.ClosePaneCommand = new RelayCommand(() => PaneHolder?.CloseActivePane()); ToolbarViewModel.CreateNewFileCommand = new RelayCommand(x => UIFilesystemHelpers.CreateFileFromDialogResultType(AddItemDialogItemType.File, x, this)); diff --git a/src/Files.Shared/Logger.cs b/src/Files.Shared/Logger.cs index 0d05f6124d68..d96fd7c39054 100644 --- a/src/Files.Shared/Logger.cs +++ b/src/Files.Shared/Logger.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.IO; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -58,19 +57,6 @@ private async void LogAsync(string type, string caller, string message, int atte { await writer.WriteLineToLogAsync($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.ffff}|{type}|{caller}|{message}"); } - catch (IOException e) when (e is not FileNotFoundException) - { - if (attemptNumber < 5) // check the attempt count to prevent a stack overflow exception - { - // Log is likely in use by another process instance, so wait then try again - await Task.Delay(50); - LogAsync(type, caller, message, attemptNumber + 1); - } - else - { - Debug.WriteLine($"Writing to log file failed after 5 attempts with the following exception:\n{e}"); - } - } catch (Exception e) { Debug.WriteLine($"Writing to log file failed with the following exception:\n{e}");