Open thomas-goerlich opened 5 years ago
Hey @thomas-goerlich,
Thanks for submitting the issue! I had no clue that Icon.FromHandle leaks in that way, so thanks for pointing that out. Looks Icon.FromHandle is used in a few places, but only this single part of WPF.
@thomas-goerlich I am trying to use the tray feature but cannot for the life of me find a working example anywhere. Any chance you got something handy?
Hey @josegomez, did you check out the official example at https://github.com/picoe/Eto/blob/develop/test/Eto.Test/Sections/Behaviors/TrayIndicatorSection.cs?
My code is still on eto.forms v2.4.1. No idea if maybe something changed in a later version.
partial class MainForm : Form
{
TrayIndicator tray = new TrayIndicator();
private void InitializeComponent()
{
[...]
ShowInTaskbar = false;
[...]
var trayMenu = new ContextMenu();
trayMenu.Items.Add(showMainWindowCommand);
trayMenu.Items.Add(showSettingsCommand);
trayMenu.Items.Add(quitCommand);
[...]
tray.Menu = trayMenu;
tray.Title = "breaktimer";
tray.Image = Icon.FromResource("breaktimer.Assets.tray.tray-paused.png");
tray.Activated += ShowMainWindow;
tray.Show();
[...]
}
}
Hope it helps :)
Thank you!
Expected Behavior
I can change the tray icon as often as i want.
Actual Behavior
After a certain amount of changes the app crashes. Granted in a normal use case i wouldn't expect anyone to reach this point 😄
Steps to Reproduce the Problem
Create an app that changes the tray icon every second or so and wait.
Code that Demonstrates the Problem
Specifications
Stacktrace
A Generic Error occurred in GDI+ at System.Drawing.Bitmap.GetHicon() at Eto.Wpf.WpfConversions.ToSDIcon(Image image) at Eto.Wpf.Forms.TrayIndicatorHandler.set_Image(Image value) at Eto.Forms.TrayIndicator.set_Image(Image value) at breaktimer.MainForm.UpdateTrayIcon(Int32 currentTime, Int32 totalTime) at breaktimer.MainForm.TimerOnTimerUpdate(Object sender, TimerEventArgs e) at breaktimer.Timer.IntervalTimerElapsed(Object sender, EventArgs e) at Eto.Forms.UITimer.OnElapsed(EventArgs e) at Eto.Forms.UITimer.Callback.OnElapsed(UITimer widget, EventArgs e) at Eto.Wpf.Forms.UITimerHandler.<.ctor>b__0_0(Object sender, EventArgs e) at System.Windows.Threading.DispatcherTimer.FireTick(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.DispatcherOperation.InvokeImpl() at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Threading.DispatcherOperation.Invoke() at System.Windows.Threading.Dispatcher.ProcessQueue() at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at System.Windows.Application.Run(Window window) at Eto.Wpf.Forms.ApplicationHandler.Run() at Eto.Forms.Application.Run(Form mainForm) at breaktimer.Wpf.MainClass.Main(String[] args) in [...]breaktimer\breaktimer\breaktimer.Wpf\Program.cs:Line 16.
I found a Stackoverflow entry which seems to match this problem: https://stackoverflow.com/questions/12026664/a-generic-error-occurred-in-gdi-when-calling-bitmap-gethicon I can confirm that the GDI objects increase by every icon change until reaching 10.000.
How i came to produce this error
I am creating a pomodoro timer app. The app lives in the tray icon area. The icon is basically a pie chart which gets filled out as time goes on. I was changing the icon every second. Resulting in the app crashing in less than an hour. Every icon change seems to increase the GDI objects by 3 to 5. I changed my code to only change the icon if the icon actually needs to change resulting in way less changes.