protected override void OnRenderItemText(System.Windows.Forms.ToolStripItemTextRenderEventArgs e) { if (!OsUtils.CompositionEnabled()) { // The OS doesn't support desktop composition, or it isn't enabled base.OnRenderItemText(e); return; } // Drawing text on glass is a bit of a pain - text generated with GDI (e.g. standard // controls) ends up being transparent as GDI doesn't understand alpha transparency. // GDI+ is fine drawing text on glass but it doesn't use ClearType, so the text ends // up looking out of place, ugly or both. The proper way is using DrawThemeTextEx, // which works fine, but requires a top-down DIB to draw to, rather than the bottom // up ones that GDI normally uses. Hence; create top-down DIB, draw text to it and // then AlphaBlend it in to the graphics object that we are rendering to. // Get the rendering HDC, and create a compatible one for drawing the text to IntPtr renderHdc = e.Graphics.GetHdc(); IntPtr memoryHdc = NativeMethods.CreateCompatibleDC(renderHdc); // NULL Pointer if (memoryHdc == IntPtr.Zero) { throw new Win32Exception(); } NativeMethods.BITMAPINFO info = default(NativeMethods.BITMAPINFO); info.biSize = Convert.ToUInt32(Marshal.SizeOf(typeof(NativeMethods.BITMAPINFO))); info.biWidth = e.TextRectangle.Width; info.biHeight = -e.TextRectangle.Height; // Negative = top-down info.biPlanes = 1; info.biBitCount = 32; info.biCompression = NativeMethods.BI_RGB; IntPtr bits = IntPtr.Zero; // Create the top-down DIB IntPtr dib = NativeMethods.CreateDIBSection(renderHdc, ref info, 0, ref bits, IntPtr.Zero, 0); // NULL Pointer if (dib == IntPtr.Zero) { throw new Win32Exception(); } // Select the created DIB into our memory DC for use // NULL Pointer if (NativeMethods.SelectObject(memoryHdc, dib) == IntPtr.Zero) { throw new Win32Exception(); } // Create a font we can use with GetThemeTextEx IntPtr hFont = e.TextFont.ToHfont(); // And select it into the DC as well // NULL Pointer if (NativeMethods.SelectObject(memoryHdc, hFont) == IntPtr.Zero) { throw new Win32Exception(); } // Fetch a VisualStyleRenderer suitable for toolbar text VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.ToolBar.Button.Normal); // Set up a RECT for the area to draw the text in NativeMethods.RECT textRect = default(NativeMethods.RECT); textRect.left = 0; textRect.top = 0; textRect.right = e.TextRectangle.Width; textRect.bottom = e.TextRectangle.Height; // Options for GetThemeTextEx NativeMethods.DTTOPTS opts = default(NativeMethods.DTTOPTS); opts.dwSize = Convert.ToUInt32(Marshal.SizeOf(opts)); opts.dwFlags = NativeMethods.DTT_COMPOSITED | NativeMethods.DTT_TEXTCOLOR; opts.crText = Convert.ToUInt32(ColorTranslator.ToWin32(e.TextColor)); // Alpha blended text of the colour specified // Paint the text Marshal.ThrowExceptionForHR(NativeMethods.DrawThemeTextEx(renderer.Handle, memoryHdc, 0, 0, e.Text, -1, (uint)e.TextFormat, ref textRect, ref opts)); // Set up the AlphaBlend copy NativeMethods.BLENDFUNCTION blendFunc = default(NativeMethods.BLENDFUNCTION); blendFunc.BlendOp = NativeMethods.AC_SRC_OVER; blendFunc.SourceConstantAlpha = 255; blendFunc.AlphaFormat = NativeMethods.AC_SRC_ALPHA; // Per-pixel alpha only // Blend the painted text into the render DC if (!NativeMethods.AlphaBlend(renderHdc, e.TextRectangle.Left, e.TextRectangle.Top, e.TextRectangle.Width, e.TextRectangle.Height, memoryHdc, 0, 0, e.TextRectangle.Width, e.TextRectangle.Height, blendFunc)) { throw new Win32Exception(); } // Clean up the GDI objects if (!NativeMethods.DeleteObject(hFont)) { throw new Win32Exception(); } if (!NativeMethods.DeleteObject(dib)) { throw new Win32Exception(); } if (!NativeMethods.DeleteDC(memoryHdc)) { throw new Win32Exception(); } e.Graphics.ReleaseHdc(); }