17

Why I'm getting "A Generic Error occurred in GDI+" Exception ?

IntPtr hicon = tempBitmap.GetHicon();             
Icon bitmapIcon = Icon.FromHandle(hicon);            
return bitmapIcon;

The error occurred when my application has been running for more than 30 minutes. (I am converting System.Drawing.Bitmap to System.Drawing.Icon every second)

enter image description here

Jeff B
  • 8,572
  • 17
  • 61
  • 140

2 Answers2

29

That's caused by a handle leak. You can diagnose the leak with TaskMgr.exe, Processes tab. View + Select Columns and tick Handles, GDI Objects and USER Objects. Observe these columns while your program is running. If my guess is right, you'll see the GDI Objects value for your process steadily climbing. When it reaches 10,000 then the show is over, Windows refuses to allow you to leak more objects.

The Remarks section for Icon.FromHandle says:

When using this method you must dispose of the resulting icon using the DestroyIcon method in the Win32 API to ensure the resources are released.

That's good advice but usually pretty painful to do. You can find a hack to force the Icon object to own the handle, and automatically release it, in this answer. Relevant code is after the "Invoke private Icon constructor" section.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • tmpIcon.Dispose() isn't this enough ? – Mohammad Reza Taesiri Aug 19 '12 at 13:28
  • No, it doesn't own the handle. Which is why I recommended the hack to force it to own the handle. Then disposing it will work. – Hans Passant Aug 19 '12 at 13:34
  • in task manager the number of Handles was 361 and dropped to 358 and now 357; and after 2 min : 345 !! – Mohammad Reza Taesiri Aug 19 '12 at 13:34
  • thank you again! i fixed the problem; GDI Objects are now around 110. you saved my life :P – Mohammad Reza Taesiri Aug 19 '12 at 14:04
  • 9
    It doesn't seem that painful: Adding 3 lines as per http://msdn.microsoft.com/en-us/library/vstudio/system.drawing.icon.fromhandle(v=vs.90).aspx appears to have solved the issue for me. – Superbest Apr 24 '13 at 07:15
  • 2
    In Windows 10, you still launch Task Manager but then you go to the Details tab and right-click the column heading to choose Select Columns. At that point you can add Handles, GDI Objects and User objects. – Jazimov Nov 20 '18 at 06:30
  • For all who are looking for an c# implementation of a hassle-free Bitmap to Icon Converter: https://gist.github.com/D4koon/2b397eca452b75115f19063560efbbb3 – Sebastian Ax Mar 05 '20 at 05:32
7

You probably need to clean up your icon.

The example for Icon.FromHandle on MSDN shows you how. Unfortunately it requires PInvoke:

[System.Runtime.InteropServices.DllImport("user32.dll", CharSet=CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);

And then inside your method:

IntPtr hicon = tempBitmap.GetHicon();             
Icon bitmapIcon = Icon.FromHandle(hicon);        

// And then somewhere later...
DestroyIcon(bitMapIcon.Handle);    

If you call DestoryIcon before you use it, it may not work. For my own particular instance of this problem, I ended up keeping a reference to the last icon I created and then called DestroyIcon on it the next time I generated an icon.

Jeff B
  • 8,572
  • 17
  • 61
  • 140
  • My experiments show, that the form must be loaded (the window handle must be created?) in order for the statement “since the form creates its own copy of the icon” from the MSDN example to be true, since if the window is not loaded, the copy will take place when it is first loaded, and if you called DestroyIcon before that, an `ObjectDisposedException` is thrown when the form tries to load the handle from the Icon. I assume that is the reason why you needed to retain a copy of the Icon. – Adam L. S. Dec 29 '20 at 13:27