Bookmark and Share Share...    Subscribe to this feed Feed   About Christian Moser  


How to extend the Aero Glass into the Client area

Introduction

Windows Vista has a new default theme called Aero glass. In Aero glass, the title bar of a window and the frame is drawn transculent. This gives the UI a clean and lightweight look. This nice feaure is provided by a service that is called the desktop window manager (DWM).

Extending the Glass

By default the blurry glass effect is only on the title bar and the frame, but the client area is drawn opaque. But there is a simple way to extend the glass into the client area by using the DWM's API.

First thing you need to do is to include some Win32 functions from the dwmapi.dll library.

 
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows;
 
[StructLayout(LayoutKind.Sequential)]
struct MARGINS
{
    public int cxLeftWidth;
    public int cxRightWidth;
    public int cyTopHeight;
    public int cyBottomHeight;
}
 
[DllImport("dwmapi.dll")]
static extern int 
   DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
 
[DllImport("dwmapi.dll")]
extern static int DwmIsCompositionEnabled(ref int en);
 
 
 

I have written a helper method that does all the stuff to extend the glass by the specified amount of pixels on each border of the window.

 
 
/// <summary>
/// Extends the glass area into the client area of the window
/// </summary>
/// <param name="window"></param>
/// <param name="top"></param>
public static void ExtendGlass(Window window, Thickness thikness)
{
    try
    {
        int isGlassEnabled = 0;
        DwmIsCompositionEnabled(ref isGlassEnabled);
        if (Environment.OSVersion.Version.Major > 5 && isGlassEnabled > 0)
        {
            // Get the window handle
            WindowInteropHelper helper = new WindowInteropHelper(window);
            HwndSource mainWindowSrc = (HwndSource)HwndSource.
                FromHwnd(helper.Handle);
            mainWindowSrc.CompositionTarget.BackgroundColor = 
                Colors.Transparent;
 
            // Get the dpi of the screen
            System.Drawing.Graphics desktop = 
               System.Drawing.Graphics.FromHwnd(mainWindowSrc.Handle);
            float dpiX = desktop.DpiX / 96;
            float dpiY = desktop.DpiY / 96;
 
            // Set Margins
            MARGINS margins = new MARGINS();
            margins.cxLeftWidth = (int)(thikness.Left * dpiX);
            margins.cxRightWidth = (int)(thikness.Right * dpiX);
            margins.cyBottomHeight = (int)(thikness.Bottom * dpiY);
            margins.cyTopHeight = (int)(thikness.Top * dpiY);
 
            window.Background = Brushes.Transparent;
 
            int hr = DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, 
                        ref margins);
        }
        else
        {
            window.Background = SystemColors.WindowBrush;
        }
    }
    catch (DllNotFoundException)
    {
 
    }
}
 
 

Next thing you need to do is calling the ExtendGlass in the OnSourceInitialized callback. Because that is the time the window handle has been created.

 
 
protected override void OnSourceInitialized(EventArgs e)
{
   base.OnSourceInitialized(e);
   GlassHelper.ExtendGlass(this, LayoutRoot.Margin);
}
 
 
 

Since the user (or the system) can enable or disable the glass effect while the application is running, we need to hook up a callback in the WndProc to undo or initialize the glass extension dynamically.

 
 
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, 
  IntPtr lParam, ref bool handled)
{
    if (msg == GlassHelper.WM_DWMCOMPOSITIONCHANGED)
    {
        GlassHelper.ExtendGlass(this, LayoutRoot.Margin);
        handled = true;
    }
    return IntPtr.Zero;
}
 
 
 




Last modified: 2009-12-16 16:45:09
Copyright (c) by Christian Moser, 2011.

 Comments on this article

Show all comments
Tim
Commented on 16.July 2009
Is it just me, or does Expression Blend 3 (RC) completely ignore the fact that there's a System.Drawing namespace? I can't make the code work, and it's just this one single part that is holding me up. It says there's no "Drawing" namespace in the "System" namespace. (???)
Tim
Commented on 16.July 2009
PS -- I got it working by removing the DPI detection (a workaround, not a fix, of course), and then it started working like a charm. thanks so much for the helper class! Lovely how it pulls the margin right off of my LayoutRoot!!
Christian Moser
Commented on 16.July 2009
Hi Tim,
The System.Drawing namespace is defined in a separate assembly called "System.Drawing". You probably forgot to add a reference to that assembly. In Blend it's a bit tricky to do this. But in Visual Studio just right-click of the "References" folder in your project and choose "Add Reference..." then select the tab ".NET" and find the "System.Drawing" entry.

I hope this helps.

Greetings
Christian
Tim
Commented on 17.July 2009
Thanks-- I'm still a bit new to C#, and my experience with Java isn't helping much at times like this :) Thanks for the tip-- I will be sure to make use of it.

By the way, do you know if there's a way to render text with the Vista/Win7 blur behind it? That is, the effect used on the gadget list when you try to add to the sidebar/desktop, or in the titlebar of a window? I've read about this for doing straight-up C/++ application programming, but I don't know if there is a way to specify such things given the interface that Blend gives you. And it would be slightly backwards if I had to programatically render the text instead of using the xaml/gui editor.

If not, I can live with it :P (or fake the effect, either way!) Thanks muchly for sharing your expertise.
Christian Moser
Commented on 17.July 2009
Hi Tim,

check out this Expression Blend Behavior: http://gallery.expression.microsoft.com/en-us/GlassBehavior

Greetings
Christian
Tim
Commented on 17.July 2009
Perfect. Thanks again. This is what I imagined it should be like :)
Matt Wilkinson
Commented on 5.August 2009
Reading over the MSDN documentation, it looks as if the whole client area will have the Aero Glass drawn under it if you set the margins to -1.

http://msdn.microsoft.com/en-us/library/aa969537%28VS.85%29.aspx#frameextend
Ankit Malhotra
Commented on 28.August 2009
Implementation in VB.NET:


Imports System.Drawing
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("dwmapi.dll", CharSet:=CharSet.Auto)> _
Public Shared Sub DwmExtendFrameIntoClientArea(ByVal hWnd As System.IntPtr, ByRef pMargins As Printing.Margins)
End Sub


Private Glass_brush As SolidBrush = New SolidBrush(Color.Black)
Private border_extensions As Printing.Margins = New Printing.Margins
'Public Structure Margins
' Public Left As Integer
' Public Right As Integer
' Public Top As Integer
' Public Bottom As Integer
'End Structure
Public Sub New()
InitializeComponent()
border_extensions.Top = 300 'amount of border extension required from top border
border_extensions.Left = 300 'amount of border extension required from left border
border_extensions.Right = 300 'amount of border extension required from right border
border_extensions.Bottom = 300 'amount of border extension required from the bottom border

DwmExtendFrameIntoClientArea(Me.Handle, border_extensions)
End Sub

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.FillRectangle(Glass_brush, New System.Drawing.Rectangle(0, 0, 300, 300))
'' painting the areas in client regions in black..if these fall in the margins described u would get
'' glass effect!
End Sub


End Class
Chris Jacobs
Commented on 20.October 2009
It seems overkill to do anything based just plainly on operating system such as vista. I work at a massive organisation and they wouldn't touch it. I havent used it so no comment, i like the glass effect. But seriously solutions should and need to be for XP and above, not just for vista. home users use vista organisations tend to stay away. And thats a fact. Why have a nice window that looks crap when majority of users use it.
mitzaodx
Commented on 24.December 2009
why does my buttons and images look weird? my pictures have no transparency and my buttons don't show like buttons... they look weird..??
mitzaodx
Commented on 27.December 2009
Fixed the buttons. I changed the color from black to navy and used a pannel to get the aero feel. I just want to know is there a way that the icons displayed in a listview can be full scale? when i set it to 32x32 they look very bad, can it be that the icons look like vista desktop icons? with that kind of select effect?
saman
Commented on 27.December 2009
thank,s
mitzaodx
Commented on 28.December 2009
Fixed the buttons. I changed the color from black to navy and used a pannel to get the aero feel. I just want to know is there a way that the icons displayed in a listview can be full scale? when i set it to 32x32 they look very bad, can it be that the icons look like vista desktop icons? with that kind of select effect?
Michał
Commented on 6.January 2010
Hi, i have a problem with "complete" implementation of this. Could You please post a link to complete source code of GlassHelper and sample Window that is to make use of it ? Thanks in advance, Michal
Tschaena
Commented on 11.January 2010
Hi Christian. Worked almost as expected ;-)
Eon
Commented on 17.April 2010
Hi Christian, thanks for a great tutorial. It works beautifully but I'm curious, just how does this look on XP? Also, I was wondering if you know a technique to also extend the ability to drag a window by clicking on the title bar over the entire new glass region. Even though the glass looks seamless I am still only able to drag a window by the region up at the top.
Bob
Commented on 26.April 2010
Hey--do this work on Win 3.1?
Jill
Commented on 27.April 2010
yes, this do work on 3.1. I am currently getting it to work on DOS
vcxv
Commented on 27.May 2010
cxv
Bill
Commented on 8.July 2010
Any possible eay to achive this with XP
Bob 2
Commented on 8.July 2010
Do this work with DOS 1.1
Bob 2
Commented on 8.July 2010
Oh.. Jill.. is doing it.. mad poor guy
QWERT
Commented on 27.October 2010
thats stolen from another site... faggot
Simba
Commented on 3.March 2011
Thanks. very nice paper
Evans
Commented on 10.May 2011
There are a couple of lines of code missing in your example to make it perfect.

First:
public const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
needs to be declared in the GlassHelper class.

Secondly:
In order for the WndProc procedure to run in WPF the following lines should be added to the windows load event since WPF windows don't have a hWnd

HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));

Otherwise the example is a nice one.


Name
E-Mail (optional)
Comment