Draw/convert HICON into Picture - Mask is wrong

I have a HICON reference (from SHGetStockIconInfo) and need to get it into a Picture.

I’ve tried using WFS 3.2, GraphicsHelpersWFS.GetStockIcon, but its IconHandleToPicture() doesn’t do this properly: Often, the icon’s mask is not copied correctly, so I end up with either a random or a completely black mask. I can’t figure out why, after spending 2 hours on this, and reading lots of WinAPI docs etc.

Does anyone know of a reliable way to get such HICONs into the Xojo world? Even saving them to disk as a png and loading them with Picture.Load would make me happy - but I can’t figure out how to export HICONs in any way.

After finding Jim’s comment, I finally figured it out - ALMOST:

The long code in GraphicsHelpersWFS.IconHandleToPicture can be replaced with this, and it’ll “just work”, at least in Windows 7:

[code] declare sub GetIconInfo Lib “User32” (hIcon as Integer, iconInfo as Ptr)
declare sub GetObjectA Lib “GDI32” (hBitmap as Ptr, size as Integer, struct as Ptr)
declare function DrawIconEx lib “User32” (hDC as integer,X as int32,Y as int32, hIcon as Integer, wx as Integer, wy as Integer, ani as Integer, brush as Integer, flags as Integer) as Boolean

const DI_MASK = 1
const DI_IMAGE = 2

if iconHandle <> 0 then
  dim iconInfo as new MemoryBlock(20)
  GetIconInfo (iconHandle, iconInfo)
  dim bitmapInfo as new MemoryBlock(24)
  GetObjectA (iconInfo.Ptr(12), 24, bitmapInfo)
  dim ret as new Picture (bitmapInfo.Long(4), bitmapInfo.Long(8), 32)
  call DrawIconEx (ret.Graphics.Handle(Graphics.HandleTypeHDC), 0, 0, iconHandle, ret.Width, ret.Height, 0, 0, DI_IMAGE)
  call DrawIconEx (ret.Mask.Graphics.Handle(Graphics.HandleTypeHDC), 0, 0, iconHandle, ret.Width, ret.Height, 0, 0, DI_MASK)
  return ret
end if[/code]

However: It doesn’t work right in Windows 10! The problem there is that the icon mask is never correct - the mask always is completely black.

Any idea why the icon mask would be right in Win 7 but not in Win 10?

If anyone wants to give it a try - here’s the complete test project (32 KB): http://files.tempel.org/RB/WFS-Icons.rbp

Is it even possible in Xojo 2016r4 or later with declares ? As in was there ever implemented something to return the HDC in pure Xojo code ? (This is needed starting at 2016r4 because of the changed graphics API under the hood)

Since without that your App will go very messed up.

Hi Björn,
I mainly test in 2012r2.1, but the same behavior is with 2017r2.1. What makes you think HDC does not work? I see no difference with 2017 and 2012 in this regard. Both work in Win 7, and both work somewhat in Win 10 (i.e. wrong mask but correct main picture).

Huh - wait. You’re right - nothing apears with 2017r2.1 in Win 10. However, it works in Win 7 with 2017r2.1.

What’s going on here? Is there a solution for 2017 on Win 10?

Basically 2016r4 you need to return the HDC after use since what is under the hood is not actually HDC’s and it is temporary created. (Thats how I understand it anyhow).

They made function in the Plugin SDK to return it, why they did not in the Xojo for those that use declares is beyond me. (Unless they added it at later time without me knowing of it)

Effect of not returning it is that things in the UI stop drawing correctly, random things might not even be your things.

This one here is the one that was added:
REALGraphicsReleaseDC

Björn, by return the value you mean to release it, right?

I actually made it work in Win10 now, and do not see the issues you mentioned, so far. My change was to use Pictures with alpha channel (which requires setting “UseGDIPlus” in older versions), and then calling DrawIcon on its HDC, without separating pic+mask as I did before. A working demo project for Win10 + Xojo 2017r2.1 is here: http://files.tempel.org/RB/WFS-Icons2.rbp

No more like what the SDK says:

/**
 * Releases the device context from memory, and more importantly, flushes the drawing
 * done on handle to our Direct2D backed surface.  This must be paired with each call
 * to Graphics.Handle or REALGraphicsDC
 *
 * @param context The graphics context to release HDC from
 */
void REALGraphicsReleaseDC(REALgraphics context);

Well, then that’d be clearly a bug if Xojo offers a function to retrieve the handle but no function to release it again. Unless the Graphics.Handle function does some magic to remedy this?