rabangus@gmail.com
November 16th, 2009, 08:39 AM
I'm working on a C# windows forms project using the glass aero effects available in Vista and Win 7, and getting the glow behind text effect using DrawThemeTextEx as per the code below. All works fine with normal aero glass, but if I add some colour to the glass (i.e. using LinearGradientBrush) the rectangle around the text is transparent does not include the colour painted with the brush.
I've done a bit of searching and reading, and it appears that CAPTUREBLT is designed to deal with this, but as mentioned in the Miscrosoft documentation it doesn't work properly with DC, which is what I'm using here.
My question therefore is is there another way of adding text using DrawThemeTextEx that will include painted layers?
public void DrawTextOnGlass(IntPtr hwnd, String text, Font font, Color forecolor, Rectangle bounds, int iglowSize, TextStyle textStyle)
{
if (VistaApi.IsCompositionEnabled())
{
RECT rc = new RECT();
RECT rc2 = new RECT();
rc.left = bounds.Left - 1 * iglowSize;
rc.right = bounds.Right + 1 * iglowSize; //make it larger to contain the glow effect
rc.top = bounds.Top - 1 * iglowSize;
rc.bottom = bounds.Bottom + 1 * iglowSize;
//Just the same rect with rc,but (0,0) at the lefttop
rc2.left = 0;
rc2.top = 0;
rc2.right = rc.right - rc.left;
rc2.bottom = rc.bottom - rc.top;
IntPtr destdc = GetDC(hwnd); //hwnd must be the handle of form, not control
IntPtr Memdc = CreateCompatibleDC(destdc); // Set up a memory DC where we'll draw the text.
IntPtr bitmap;
IntPtr bitmapOld = IntPtr.Zero;
IntPtr logfnotOld;
int uFormat = DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX; //text format
BITMAPINFO dib = new BITMAPINFO();
dib.bmiHeader.biHeight = -(rc.bottom - rc.top); // negative because DrawThemeTextEx() uses a top-down DIB
dib.bmiHeader.biWidth = rc.right - rc.left;
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER));
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
if (!(SaveDC(Memdc) == 0))
{
bitmap = CreateDIBSection(destdc, ref dib, DIB_RGB_COLORS, 0, IntPtr.Zero, 0); // Create a 32-bit bmp for use in offscreen drawing when glass is on
if (!(bitmap == IntPtr.Zero))
{
bitmapOld = SelectObject(Memdc, bitmap);
IntPtr hFont = font.ToHfont();
logfnotOld = SelectObject(Memdc, hFont);
try
{
System.Windows.Forms.VisualStyles.VisualStyleRenderer renderer = new System.Windows.Forms.VisualStyles.VisualStyleRenderer(System.Windows.Forms.VisualStyles.VisualStyleElement.Window.Caption.Active);
DTTOPTS dttOpts = new DTTOPTS();
if (textStyle == TextStyle.Glowing)
{
dttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE | DTT_TEXTCOLOR;
}
else
{
dttOpts.dwFlags = DTT_COMPOSITED | DTT_TEXTCOLOR;
}
uint dwRop = SRCCOPY | CAPTUREBLT;
//Set the color of the text
uint key = (uint)((forecolor.A << 24) |
(forecolor.R << 0) |
(forecolor.G << 8) |
(forecolor.B << 16));
dttOpts.crText = key;
dttOpts.dwSize = (uint)Marshal.SizeOf(typeof(DTTOPTS));
dttOpts.iGlowSize = iglowSize;
DrawThemeTextEx(renderer.Handle, Memdc, 0, 0, text, -1, uFormat, ref rc2, ref dttOpts);
BitBlt(destdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, Memdc, 0, 0, dwRop);
}
catch (Exception e)
{
Trace.WriteLine(e.Message);
}
//Remember to clean up
SelectObject(Memdc, bitmapOld);
SelectObject(Memdc, logfnotOld);
DeleteObject(bitmap);
DeleteObject(hFont);
ReleaseDC(Memdc, -1);
DeleteDC(Memdc);
}
}
}
}
I've attached the project if anyone wants to take a look.
Cheers
Rowan
I've done a bit of searching and reading, and it appears that CAPTUREBLT is designed to deal with this, but as mentioned in the Miscrosoft documentation it doesn't work properly with DC, which is what I'm using here.
My question therefore is is there another way of adding text using DrawThemeTextEx that will include painted layers?
public void DrawTextOnGlass(IntPtr hwnd, String text, Font font, Color forecolor, Rectangle bounds, int iglowSize, TextStyle textStyle)
{
if (VistaApi.IsCompositionEnabled())
{
RECT rc = new RECT();
RECT rc2 = new RECT();
rc.left = bounds.Left - 1 * iglowSize;
rc.right = bounds.Right + 1 * iglowSize; //make it larger to contain the glow effect
rc.top = bounds.Top - 1 * iglowSize;
rc.bottom = bounds.Bottom + 1 * iglowSize;
//Just the same rect with rc,but (0,0) at the lefttop
rc2.left = 0;
rc2.top = 0;
rc2.right = rc.right - rc.left;
rc2.bottom = rc.bottom - rc.top;
IntPtr destdc = GetDC(hwnd); //hwnd must be the handle of form, not control
IntPtr Memdc = CreateCompatibleDC(destdc); // Set up a memory DC where we'll draw the text.
IntPtr bitmap;
IntPtr bitmapOld = IntPtr.Zero;
IntPtr logfnotOld;
int uFormat = DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOPREFIX; //text format
BITMAPINFO dib = new BITMAPINFO();
dib.bmiHeader.biHeight = -(rc.bottom - rc.top); // negative because DrawThemeTextEx() uses a top-down DIB
dib.bmiHeader.biWidth = rc.right - rc.left;
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER));
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
if (!(SaveDC(Memdc) == 0))
{
bitmap = CreateDIBSection(destdc, ref dib, DIB_RGB_COLORS, 0, IntPtr.Zero, 0); // Create a 32-bit bmp for use in offscreen drawing when glass is on
if (!(bitmap == IntPtr.Zero))
{
bitmapOld = SelectObject(Memdc, bitmap);
IntPtr hFont = font.ToHfont();
logfnotOld = SelectObject(Memdc, hFont);
try
{
System.Windows.Forms.VisualStyles.VisualStyleRenderer renderer = new System.Windows.Forms.VisualStyles.VisualStyleRenderer(System.Windows.Forms.VisualStyles.VisualStyleElement.Window.Caption.Active);
DTTOPTS dttOpts = new DTTOPTS();
if (textStyle == TextStyle.Glowing)
{
dttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE | DTT_TEXTCOLOR;
}
else
{
dttOpts.dwFlags = DTT_COMPOSITED | DTT_TEXTCOLOR;
}
uint dwRop = SRCCOPY | CAPTUREBLT;
//Set the color of the text
uint key = (uint)((forecolor.A << 24) |
(forecolor.R << 0) |
(forecolor.G << 8) |
(forecolor.B << 16));
dttOpts.crText = key;
dttOpts.dwSize = (uint)Marshal.SizeOf(typeof(DTTOPTS));
dttOpts.iGlowSize = iglowSize;
DrawThemeTextEx(renderer.Handle, Memdc, 0, 0, text, -1, uFormat, ref rc2, ref dttOpts);
BitBlt(destdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, Memdc, 0, 0, dwRop);
}
catch (Exception e)
{
Trace.WriteLine(e.Message);
}
//Remember to clean up
SelectObject(Memdc, bitmapOld);
SelectObject(Memdc, logfnotOld);
DeleteObject(bitmap);
DeleteObject(hFont);
ReleaseDC(Memdc, -1);
DeleteDC(Memdc);
}
}
}
}
I've attached the project if anyone wants to take a look.
Cheers
Rowan