From 0b37aeaad7a810360e1d72a3972724a8f8e02ef1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 00:49:39 +0000 Subject: [PATCH 1/3] Initial plan From 90e9c18543db37a76427cd642a973ea553037785 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 00:54:26 +0000 Subject: [PATCH 2/3] Extract duplicated task waiting logic into WaitForTaskCompletion helper method Co-authored-by: magicxor <8275793+magicxor@users.noreply.github.com> --- WinSyncScroll/ViewModels/MainViewModel.cs | 64 ++++++++--------------- 1 file changed, 21 insertions(+), 43 deletions(-) diff --git a/WinSyncScroll/ViewModels/MainViewModel.cs b/WinSyncScroll/ViewModels/MainViewModel.cs index 1dbbabc..b57ee79 100644 --- a/WinSyncScroll/ViewModels/MainViewModel.cs +++ b/WinSyncScroll/ViewModels/MainViewModel.cs @@ -545,29 +545,16 @@ public void HandleWindowClosing() } } - public void Dispose() + private void WaitForTaskCompletion(Task? task, string taskName, TimeSpan timeout) { - AppState = AppState.NotRunning; - try - { - _cancellationTokenSource.Cancel(); - } - catch (Exception e) - { - _logger.LogError(e, "Error cancelling the cancellation token source"); - } - - // Wait for tasks to complete before disposing resources - // Using Task.Wait in Dispose is acceptable as this is a shutdown scenario - // and we need to ensure tasks complete before disposing underlying resources #pragma warning disable VSTHRD002 // Synchronously waiting is acceptable in Dispose method try { - if (_updateMouseHookRectsLoopTask is not null - && !_updateMouseHookRectsLoopTask.IsCompleted - && !_updateMouseHookRectsLoopTask.Wait(TimeSpan.FromSeconds(5))) + if (task is not null + && !task.IsCompleted + && !task.Wait(timeout)) { - _logger.LogWarning("Update mouse hook rects loop task did not complete within timeout"); + _logger.LogWarning("{TaskName} did not complete within timeout", taskName); } } catch (AggregateException ae) @@ -576,47 +563,38 @@ public void Dispose() { if (ex is OperationCanceledException) { - _logger.LogDebug("Update mouse hook rects loop was cancelled"); + _logger.LogDebug("{TaskName} was cancelled", taskName); return true; } - _logger.LogError(ex, "Error waiting for update mouse hook rects loop task"); + _logger.LogError(ex, "Error waiting for {TaskName} to complete", taskName); return true; }); } catch (Exception e) { - _logger.LogError(e, "Error disposing update mouse hook rects loop task"); + _logger.LogError(e, "Error waiting for {TaskName} to complete", taskName); } +#pragma warning restore VSTHRD002 + } + public void Dispose() + { + AppState = AppState.NotRunning; try { - if (_mouseEventProcessingLoopTask is not null - && !_mouseEventProcessingLoopTask.IsCompleted - && !_mouseEventProcessingLoopTask.Wait(TimeSpan.FromSeconds(5))) - { - _logger.LogWarning("Mouse event processing loop task did not complete within timeout"); - } - } - catch (AggregateException ae) - { - ae.Handle(ex => - { - if (ex is OperationCanceledException) - { - _logger.LogDebug("Mouse event processing loop was cancelled"); - return true; - } - - _logger.LogError(ex, "Error waiting for mouse event processing loop task"); - return true; - }); + _cancellationTokenSource.Cancel(); } catch (Exception e) { - _logger.LogError(e, "Error disposing mouse event processing loop task"); + _logger.LogError(e, "Error cancelling the cancellation token source"); } -#pragma warning restore VSTHRD002 + + // Wait for tasks to complete before disposing resources + // Using Task.Wait in Dispose is acceptable as this is a shutdown scenario + // and we need to ensure tasks complete before disposing underlying resources + WaitForTaskCompletion(_updateMouseHookRectsLoopTask, "Update mouse hook rects loop task", TimeSpan.FromSeconds(5)); + WaitForTaskCompletion(_mouseEventProcessingLoopTask, "Mouse event processing loop task", TimeSpan.FromSeconds(5)); // Dispose tasks after they have completed _updateMouseHookRectsLoopTask?.Dispose(); From 52c0b34c60056ec59c014c14e4442abfe5ad874e Mon Sep 17 00:00:00 2001 From: Ilia Burakov Date: Mon, 24 Nov 2025 09:05:19 +0800 Subject: [PATCH 3/3] Update WinSyncScroll/ViewModels/MainViewModel.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- WinSyncScroll/ViewModels/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WinSyncScroll/ViewModels/MainViewModel.cs b/WinSyncScroll/ViewModels/MainViewModel.cs index b57ee79..a36b5c8 100644 --- a/WinSyncScroll/ViewModels/MainViewModel.cs +++ b/WinSyncScroll/ViewModels/MainViewModel.cs @@ -547,7 +547,7 @@ public void HandleWindowClosing() private void WaitForTaskCompletion(Task? task, string taskName, TimeSpan timeout) { -#pragma warning disable VSTHRD002 // Synchronously waiting is acceptable in Dispose method +#pragma warning disable VSTHRD002 // Synchronously waiting is acceptable in shutdown scenarios try { if (task is not null