From 3ec36bfd35a8842b58b86e9711d1067d63f193c0 Mon Sep 17 00:00:00 2001 From: Leon Zhou Date: Fri, 10 Jan 2025 19:35:35 +1100 Subject: [PATCH] Alternative fix for COMException MILERR_WIN32ERROR and correctly use refresh interval when the app starts up. --- App/Extensions/NotifyIconExtensions.cs | 32 +++++++++++++++----------- App/NotifyIconWindow.xaml.cs | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/App/Extensions/NotifyIconExtensions.cs b/App/Extensions/NotifyIconExtensions.cs index d58582e..cefd032 100644 --- a/App/Extensions/NotifyIconExtensions.cs +++ b/App/Extensions/NotifyIconExtensions.cs @@ -40,19 +40,23 @@ internal static void SetIcon(this NotifyIcon notifyIcon, FrameworkElement textBl // Render the element with the correct DPI scale. var dpiScale = VisualTreeHelper.GetDpi(textBlock); - // There's a chance that some native exceptions may be thrown when rendering and setting the icon's image. - // Catch any exception here and retry a few times then fail silently. - DelegateExtensions.RetryOnException(() => - { - var renderTargetBitmap = new RenderTargetBitmap( - (int)Math.Round(DefaultNotifyIconSize * dpiScale.DpiScaleX, MidpointRounding.AwayFromZero), - (int)Math.Round(DefaultNotifyIconSize * dpiScale.DpiScaleY, MidpointRounding.AwayFromZero), - dpiScale.PixelsPerInchX, - dpiScale.PixelsPerInchY, - PixelFormats.Default); - renderTargetBitmap.Render(textBlock); - notifyIcon.Icon = renderTargetBitmap; - App.SetTrayIconUpdateError(null); - }, App.SetTrayIconUpdateError); + // There's a known issue that keep creating RenderTargetBitmap in a WPF app, the COMException: MILERR_WIN32ERROR + // may happen. + // This is reported as https://github.com/dotnet/wpf/issues/3067. + // Manually forcing a GC seems to help. + var renderTargetBitmap = + new RenderTargetBitmap( + (int)Math.Round(DefaultNotifyIconSize * dpiScale.DpiScaleX, MidpointRounding.AwayFromZero), + (int)Math.Round(DefaultNotifyIconSize * dpiScale.DpiScaleY, MidpointRounding.AwayFromZero), + dpiScale.PixelsPerInchX, + dpiScale.PixelsPerInchY, + PixelFormats.Default); + renderTargetBitmap.Render(textBlock); + + // Force GC after each RenderTargetBitmap creation to avoid running into COMException: MILERR_WIN32ERROR. + GC.Collect(); + GC.WaitForPendingFinalizers(); + + notifyIcon.Icon = renderTargetBitmap; } } \ No newline at end of file diff --git a/App/NotifyIconWindow.xaml.cs b/App/NotifyIconWindow.xaml.cs index 866dbeb..b046551 100644 --- a/App/NotifyIconWindow.xaml.cs +++ b/App/NotifyIconWindow.xaml.cs @@ -42,7 +42,7 @@ public NotifyIconWindow() InitializeComponent(); // Setup timer to update the tray icon. - _refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) }; + _refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(Default.RefreshSeconds) }; _refreshTimer.Tick += (_, _) => _batteryStatusUpdateSubject.OnNext(false); }