0

I've seen similar questions but none satisfies my scenario.

I am fixing a GDI Objects leak on a C++ Windows Form Application.

This is the Exception it throws:

A generic error occurred in GDI+. at System.Drawing.Bitmap.GetHicon()

This is the GetHicon call at the line where the crash happens:

this->notifyIcon1->Icon=Icon->FromHandle(((Bitmap^)imgsApp->Images[0])->GetHicon());

After doing some reading here, and on https://learn.microsoft.com/en-us/dotnet/api/system.drawing.icon.fromhandle?view=net-5.0, I see I need to call DestroyIcon() in order to release the Icon Handle (not sure if the wording is correct here), but I am having trouble doing this not being familiar with Windows Form.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • The documentation you linked to literally shows an example of using `DestroyIcon()`. As does the documentation for [`Bitmap::GetHIcon()`](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.gethicon?view=net-5.0) – Remy Lebeau Mar 23 '21 at 17:46
  • Related/Dup: [Icon.FromHandle: should I Dispose it, or call DestroyIcon?](https://stackoverflow.com/questions/30979653/) – Remy Lebeau Mar 23 '21 at 17:51

1 Answers1

1

Try this:

IntPtr iconHandle = ((Bitmap^)imgsApp->Images[0])->GetHicon();
Icon ^newIcon = Icon::FromHandle(iconHandle);
this->notifyIcon1->Icon = (Icon^) newIcon->Clone();
newIcon->Dispose();
DestroyIcon((HICON)iconHandle.ToPointer());

Per Icon.FromHandle: should I Dispose it, or call DestroyIcon?:

Conclusion: After Icon.FromHandle, the field ownHandle is false, and thus Dispose / FromHandle won't call DestroyIcon

Therefore: if you create an Icon using Icon.FromHandle you'll have to Dispose() the Icon as well as call DestroyIcon, just as the remarks section says

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I see what you did and this this should work however I get: identifier "tempManagedRes" is not defined. I guess this has to be defined prior to this? – Ernesto Jorge Mar 23 '21 at 19:28
  • Thanks for the update. The iconHandle initialized in your example get the HICON in the first line, however when calling DestroyIcon(iconHandle) it causes the following error: no suitable conversion function from "System::IntPtr" to "HICON" exists – Ernesto Jorge Mar 23 '21 at 21:18
  • @ErnestoJorge `Bitmap::GetHIcon()` returns an `IntPtr` not an `HICON` (which is either `struct HICON__*` or `void*` depending on whether [`STRICT`](https://learn.microsoft.com/en-us/windows/win32/winprog/strict-type-checking) is enabled or not, respectively). You must be calling the actual Win32 API C declaration of `DestroyIcon()` rather than a PInvoke version of it. You will have to use a type-cast, eg `DestroyIcon((HICON)iconHandle);` (I don't use **Managed** C++). – Remy Lebeau Mar 23 '21 at 22:07
  • A type-cast results in the same since there is no conversion from IntPtr to HICON. This does not matches the documentation [link](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.gethicon?view=net-5.0) as they call `destroyIcon(newIcon->Handle)` and doing this in my code also results on "no suitable conversion". If `Bitmap::GetHicon()` returns an IntPtr how is the documentation calling `DestroyIcon()` on it? I will keep looking into this and update once I find something else. – Ernesto Jorge Mar 23 '21 at 22:38
  • @ErnestoJorge `Icon::Handle` is also an `IntPtr`. The documentation is showing code examples in C#, not in C++ (there is no `->` operator in C#), where `DestroyIcon()` is called via PInvoke using an `IntPtr` parameter. In C++, try using [`IntPtr::ToPointer()`](https://learn.microsoft.com/en-us/dotnet/api/system.intptr.topointer), eg: `DestroyIcon((HICON)iconHandle.ToPointer());` – Remy Lebeau Mar 23 '21 at 23:14