HavenDV/H.NotifyIcon

System.InvalidOperationException: UpdateIcon failed can be thrown when updating GeneratedIcon Text while waking from sleep

PikeUK opened this issue · 1 comments

Describe the bug

Disclaimer: Not sure if this can be considered a bug in the library or not but I've reported it just to be thorough. It's easy enough for my software to catch this exception but it would be nice if the library could handle this itself.

If you try to update the generated icon text via a timer and the PC is put to sleep for longer than the timer interval then when you wake up the PC a "System.InvalidOperationException: UpdateIcon failed" will be thrown.

Steps to reproduce the bug

  1. Create a project with a tray icon and using a DispatcherTimer to call an event handler every minute. In the event handler call something like:
    myGeneratedIcon.Text = "test";
  2. While running this code sleep the PC for 2 minutes then wake it up.

Expected behavior

The icon text should be updated instead an exception is thrown.

Screenshots

No response

NuGet package version

2.0.68

Platform

WPF

IDE

Visual Studio 2022

Windows Version

Windows 11

WindowsAppSDK Version

No response

WindowsAppSDK Type

No response

Manifest

No response

Additional context

The thrown exception:

Description: The process was terminated due to an unhandled exception. Exception Info: System.InvalidOperationException: UpdateIcon failed. at H.NotifyIcon.Core.TrayIcon.UpdateIcon(IntPtr handle) in /_/src/libs/H.NotifyIcon/Core/TrayIcon.cs:line 389 at H.NotifyIcon.TaskbarIcon.UpdateIcon(Icon value) in /_/src/libs/H.NotifyIcon.Shared/TaskbarIcon.Properties.cs:line 50 at H.NotifyIcon.GeneratedIcon.OnIconChanged(Icon oldValue, Icon newValue) in /_/src/libs/H.NotifyIcon.Shared/GeneratedIcon.cs:line 102 at H.NotifyIcon.GeneratedIcon.<>c.<.cctor>b__75_15(DependencyObject sender, DependencyPropertyChangedEventArgs args) in /_/src/libs/H.NotifyIcon.Wpf/DependencyPropertyGenerator/H.Generators.DependencyPropertyGenerator/GeneratedIcon.Properties.Icon.generated.cs:line 22 at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value) at H.NotifyIcon.GeneratedIcon.set_Icon(Icon value) in /_/src/libs/H.NotifyIcon.Wpf/DependencyPropertyGenerator/H.Generators.DependencyPropertyGenerator/GeneratedIcon.Properties.Icon.generated.cs:line 39 at H.NotifyIcon.GeneratedIcon.Refresh() in /_/src/libs/H.NotifyIcon.Shared/GeneratedIcon.cs:line 129 at H.NotifyIcon.GeneratedIcon.<>c.<.cctor>b__75_0(DependencyObject sender, DependencyPropertyChangedEventArgs args) in /_/src/libs/H.NotifyIcon.Wpf/DependencyPropertyGenerator/H.Generators.DependencyPropertyGenerator/GeneratedIcon.Properties.Text.generated.cs:line 22 at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value) at H.NotifyIcon.GeneratedIcon.set_Text(String value) in /_/src/libs/H.NotifyIcon.Wpf/DependencyPropertyGenerator/H.Generators.DependencyPropertyGenerator/GeneratedIcon.Properties.Text.generated.cs:line 38

Thank you. I guess we can track it at the Core level of the library according to this code and do a check:

SystemEvents.PowerModeChanged += OnPowerChange;

void OnPowerChange(Object sender, PowerModeChangedEventArgs e) {
  switch ( e.Mode ) {
    case PowerModes.Resume: 
      ...
    case PowerModes.Suspend:
      ...
  }
}

References:
https://stackoverflow.com/questions/1562474/how-do-i-check-when-the-computer-is-being-put-to-sleep-or-wakes-up
https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.systemevents.powermodechanged?redirectedfrom=MSDN&view=dotnet-plat-ext-6.0
https://www.nuget.org/packages/Microsoft.Win32.SystemEvents/

if (!TrayIconMethods.TryModifyIcon(Id, handle))
{
throw new InvalidOperationException("UpdateIcon failed.");
}

I will be grateful to you if you can issue it as a PR.