From 1a87e103bce8e8099f707fd3762b2172e0812e3e Mon Sep 17 00:00:00 2001 From: laurentiu021 Date: Fri, 12 Jun 2026 17:49:53 +0300 Subject: [PATCH] fix: handle Storage-WMI COM errors, dispose explorer handle, log swallowed exceptions --- CHANGELOG.md | 7 ++++++- SysManager/SysManager/Services/DeepCleanupService.cs | 4 +++- SysManager/SysManager/Services/DiskHealthService.cs | 5 +++++ SysManager/SysManager/Services/ProcessManagerService.cs | 3 ++- SysManager/SysManager/Services/SystemInfoService.cs | 5 +++-- SysManager/SysManager/Services/UpdateService.cs | 4 ++-- SysManager/SysManager/Services/WindowsUpdateService.cs | 4 ++-- SysManager/SysManager/SysManager.csproj | 6 +++--- SysManager/SysManager/ViewModels/DashboardViewModel.cs | 2 +- 9 files changed, 27 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96264d4..6367a96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,12 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -## [1.20.21] - 2026-06-12 +## [1.20.22] - 2026-06-12 + +### Fixed +- **Drive/disk health reads survive systems without the Storage WMI namespace.** Disk Health and System Info could throw an unhandled COM error on older or headless Windows where the `root\Microsoft\Windows\Storage` namespace isn't present; both now handle that case and fall back gracefully (mirrors the earlier Fixed Drives fix). +- **No leaked process handle when opening a file location.** "Open file location" in Process Manager left the launched Explorer process handle undisposed; it's now released. +- **Swallowed errors are now diagnosable.** Several silent `catch` blocks now log at Debug level with the full exception (update-file cleanup, Deep Cleanup directory deletion, Windows Update size extraction, and the Dashboard polling loop), so failures leave a trace in the log instead of vanishing. ### Changed - **Some status/accent colors now follow the theme instead of being hardcoded.** Replaced hardcoded color values that exactly matched a theme color (success green, warning amber, danger red, accent, hover border) with theme references on the Dashboard, Network Repair, Privacy, and Uninstaller tabs. The colors render identically today but will track the theme going forward. diff --git a/SysManager/SysManager/Services/DeepCleanupService.cs b/SysManager/SysManager/Services/DeepCleanupService.cs index 63a0656..a162b06 100644 --- a/SysManager/SysManager/Services/DeepCleanupService.cs +++ b/SysManager/SysManager/Services/DeepCleanupService.cs @@ -361,7 +361,9 @@ private static CleanupResult Clean(IReadOnlyList categories, IP } foreach (var dir in EnumerateDirectoriesDepthFirst(path, ct)) { - try { Directory.Delete(dir, recursive: false); } catch (IOException) { } catch (UnauthorizedAccessException) { } + try { Directory.Delete(dir, recursive: false); } + catch (IOException ex) { Log.Debug(ex, "Deep cleanup: failed to delete directory {Dir}", dir); } + catch (UnauthorizedAccessException ex) { Log.Debug(ex, "Deep cleanup: access denied deleting directory {Dir}", dir); } } } catch (Exception ex) diff --git a/SysManager/SysManager/Services/DiskHealthService.cs b/SysManager/SysManager/Services/DiskHealthService.cs index 332a8d7..735d71d 100644 --- a/SysManager/SysManager/Services/DiskHealthService.cs +++ b/SysManager/SysManager/Services/DiskHealthService.cs @@ -63,6 +63,11 @@ private static IReadOnlyList Collect() { // WMI access denied without elevation. } + catch (System.Runtime.InteropServices.COMException) + { + // scope.Connect() can throw COMException when the Storage WMI namespace + // is unavailable (older/headless Windows). Non-fatal — return what we have. + } return results; } diff --git a/SysManager/SysManager/Services/ProcessManagerService.cs b/SysManager/SysManager/Services/ProcessManagerService.cs index 8b30fbf..43cb23d 100644 --- a/SysManager/SysManager/Services/ProcessManagerService.cs +++ b/SysManager/SysManager/Services/ProcessManagerService.cs @@ -126,12 +126,13 @@ public static void OpenFileLocation(string filePath) if (string.IsNullOrWhiteSpace(filePath) || !System.IO.File.Exists(filePath)) return; try { + // Dispose the returned Process handle — we don't track the launched explorer. Process.Start(new ProcessStartInfo { FileName = "explorer.exe", Arguments = $"/select,\"{filePath}\"", UseShellExecute = true - }); + })?.Dispose(); } catch (InvalidOperationException ex) { Log.Warning(ex, "Failed to open file location: {Path}", filePath); } catch (System.ComponentModel.Win32Exception ex) { Log.Warning(ex, "Failed to open file location: {Path}", filePath); } diff --git a/SysManager/SysManager/Services/SystemInfoService.cs b/SysManager/SysManager/Services/SystemInfoService.cs index bd2ba41..e2ad432 100644 --- a/SysManager/SysManager/Services/SystemInfoService.cs +++ b/SysManager/SysManager/Services/SystemInfoService.cs @@ -226,9 +226,10 @@ private static List QueryDisks() } } } - catch (ManagementException) + catch (Exception ex) when (ex is ManagementException or System.Runtime.InteropServices.COMException) { - // Fallback to Win32_DiskDrive if MSFT_PhysicalDisk isn't available + // Fallback to Win32_DiskDrive if MSFT_PhysicalDisk / the Storage WMI namespace + // isn't available (older/headless Windows — scope.Connect() throws COMException). using var s = new ManagementObjectSearcher("SELECT Model,Size,Status FROM Win32_DiskDrive"); using var fallbackCollection = s.Get(); foreach (ManagementObject mo in fallbackCollection) diff --git a/SysManager/SysManager/Services/UpdateService.cs b/SysManager/SysManager/Services/UpdateService.cs index bdf9b64..4ed810a 100644 --- a/SysManager/SysManager/Services/UpdateService.cs +++ b/SysManager/SysManager/Services/UpdateService.cs @@ -342,8 +342,8 @@ public static bool VerifyAuthenticode(string filePath) private static void CleanupFile(string path) { try { if (File.Exists(path)) File.Delete(path); } - catch (IOException) { } - catch (UnauthorizedAccessException) { } + catch (IOException ex) { Serilog.Log.Debug(ex, "Update cleanup: could not delete {Path}", path); } + catch (UnauthorizedAccessException ex) { Serilog.Log.Debug(ex, "Update cleanup: access denied deleting {Path}", path); } } // ---------- internals ---------- diff --git a/SysManager/SysManager/Services/WindowsUpdateService.cs b/SysManager/SysManager/Services/WindowsUpdateService.cs index ff7cdcf..b1f6e83 100644 --- a/SysManager/SysManager/Services/WindowsUpdateService.cs +++ b/SysManager/SysManager/Services/WindowsUpdateService.cs @@ -233,8 +233,8 @@ internal static UpdateEntry MapToEntry(dynamic u) var kb = kbList.Count > 0 ? "KB" + string.Join(",", kbList) : string.Empty; long size = 0; try { size = (long)(decimal)u.MaxDownloadSize; } - catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { } - catch (COMException) { } + catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex) { Serilog.Log.Debug(ex, "Windows Update: MaxDownloadSize not exposed for {Title}", title); } + catch (COMException ex) { Serilog.Log.Debug(ex, "Windows Update: COM error reading size for {Title}", title); } return new UpdateEntry { Title = title, diff --git a/SysManager/SysManager/SysManager.csproj b/SysManager/SysManager/SysManager.csproj index 609ee49..84e479c 100644 --- a/SysManager/SysManager/SysManager.csproj +++ b/SysManager/SysManager/SysManager.csproj @@ -10,9 +10,9 @@ SysManager true NU1603;NU1701 - 1.20.21 - 1.20.21.0 - 1.20.21.0 + 1.20.22 + 1.20.22.0 + 1.20.22.0 SysManager SysManager — Windows system monitoring toolkit by laurentiu021. Network, updates, health, logs, safe deep cleanup. https://github.com/laurentiu021/SystemManager diff --git a/SysManager/SysManager/ViewModels/DashboardViewModel.cs b/SysManager/SysManager/ViewModels/DashboardViewModel.cs index 8a7b015..cc719ad 100644 --- a/SysManager/SysManager/ViewModels/DashboardViewModel.cs +++ b/SysManager/SysManager/ViewModels/DashboardViewModel.cs @@ -144,7 +144,7 @@ private void StartPollingLoop() catch (OperationCanceledException) { break; } catch (Exception ex) { - Log.Debug("Dashboard polling error: {Error}", ex.Message); + Log.Debug(ex, "Dashboard polling error"); await Task.Delay(1000, ct); } }