Why do my tree control icons lose transparency?

I noticed this problem while I was developing a network configurator application for our next-generation system. I was using alpha-blended icons to indicate disabled hardware in a tree control, and testing under Vista. Imagine my confusion when I noticed the icons losing their tranparency as I moused over the tree control expander buttons.

I posted the issue to microsoft.public.vc.mfc (since there isn't a common controls group on the Microsoft public Usenet server). Once I'd added a repro application, people started seeing the issue not just on Vista, but on XP as well - the only difference being that on XP you had to actually USE the buttons to see the loss of transparency. It appears that the out-of-box paint behaviour on the tree common control just doesn't play nice with alpha-blended icons. It'll make a mess of your nice drop-shadows :-(

If you have Visual Studio 2008, you can download my repro project here and have a play. Note that it's tricky to make your own version because the primitive icon editor in Visual Studio can't create alpha-blended icons, even after all these years. You need a third party tool like the excellent freeware IcoFx to do that.

Fortunately there's a couple of ways to avoid this problem. Firstly, you can use the theming functionality to fully theme the tree control. Theming makes changes to the way the control paints which will silently fix the issue (at least on NT6, I haven't tried this on NT5). Time for some code. Assume the tree control has a DDX variable declared, named m_ctrl_treeAdapters:

// Use this code for Vista's triangular tree buttons.

::SetWindowTheme(m_ctrl_treeAdapters, L"explorer", 0);

However, if you already use a third party themer, your corporate guidelines mandate an XP style, or you just prefer the old tree button appearance like me, you can set the tree control's double-buffering extended style bit:

// Use this code for old-style tree buttons, it fixes a bug in 
// tree control painting when old-style buttons are in use.

DWORD dwStyleBits;
dwStyleBits = m_ctrl_treeAdapters.GetExtendedStyle();
dwStyleBits |= TVS_EX_DOUBLEBUFFER;
m_ctrl_treeAdapters.SetExtendedStyle (0, dwStyleBits);