Extending Aero Glass from Non-Client Area into Client Area

Post Reply
User avatar
Click16
Posts: 1941
Joined: Mon Dec 31, 2007 4:36 am
Location: United States

Extending Aero Glass from Non-Client Area into Client Area

Post by Click16 »

Hey everyone, Today I will be showing you how you can extend the Windows Aero Glass frame into the Client Area.

The non-client area is the border, where the icon, title, minimize button, maximize/restore button, and close button is located. Using some simple API's we can extend the glass into the client area.

Obviously you would want to use Windows Vista or Windows 7 for this. There is no point running this on XP or lower.

Section 1: Setting up Project and Creating the Vista API Class

1) Create a Windows Forms Application in Visual Studio using C#.
2) Go to the Solution Explorer and add a class to the current project. Name it Vista API.cs.
3) Remove the class so you end up with this.

Code: Select all

namespace <Don't Change>
{

}
4) Now we need to import our DLL files.
5) add an Internal Class named VistaAPI.

Code: Select all

namespace GlassTutorial
{
    internal class VistaAPI
    {
    }
}
6) Now we need to Create our Margins the Extended frame will use.

Code: Select all

        internal struct Margins
        {
            public int Left, Right, Top, Bottom;
        }
Add that so it looks like this:

Code: Select all

    internal class VistaAPI
    {
        internal struct Margins
        {
            public int Left, Right, Top, Bottom;
        }
    }

7) Now we need to use "Using System.Runtime.InteropServices"

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
Now lets Import a couple of DLL's.

Code: Select all

    internal class VistaAPI
    {
        [DllImport("dwmapi.dll")]
        internal static extern void DwmExtendFrameIntoClientArea(
        System.IntPtr hWnd, ref Margins pMargins);

        [DllImport("dwmapi.dll")]
        public extern static int DwmIsCompositionEnabled(ref bool isEnabled);

    }
DwmAPI stands for "Desktop Windows Manager API."

You also might want to add a summary above the DLL Imports.

Code: Select all

    internal class VistaAPI
    {
        /// <summary>
        /// Extending frame into the Margins
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="pMargins"></param>
        [DllImport("dwmapi.dll")]
        internal static extern void DwmExtendFrameIntoClientArea(
        System.IntPtr hWnd, ref Margins pMargins);

        /// <summary>
        /// Checking if Desktop Composition is Enabled
        /// </summary>
        /// <param name="isEnabled"></param>
        /// <returns></returns>
        [DllImport("dwmapi.dll")]
        public extern static int DwmIsCompositionEnabled(ref bool isEnabled);

        /// <summary>
        /// Setting up the Margins that DwmExtendFrameIntoClientArea will use
        /// </summary>
        internal struct Margins
        {
            public int Left, Right, Top, Bottom;
        }
    }
8) Add these constants under your margins structure.

Code: Select all

        internal const int WM_NCHITTEST = 0x84;
        internal const int HTCLIENT = 1;
        internal const int HTCAPTION = 2;
Those will help you out later on.

Section 2: Setting up the Form to use Extended Frame

1) Don't add any controls to Form1 yet. First we just want to view the code. So right click and press View code.

2) You should only see the Constructor and the partial class.

3) Add these lines above the Constructor.

Code: Select all

        //Margins API Call
        private VistaAPI.Margins marg;
        //Creating Glass Rectangle
        private Rectangle toprect = Rectangle.Empty;
So now you should have something like this:

Code: Select all

    public partial class Form1 : Form
    {
        //Margins API Call
        private VistaAPI.Margins marg;
        //Creating Glass Rectangle
        private Rectangle toprect = Rectangle.Empty;

        public Form1()
        {
            InitializeComponent();
        }
    }
4) Now lets extend the frame into the client area.

But first, we need a Boolean to tell whether glass is enabled or not.

Code: Select all

        private bool IsGlassEnabled()
        {
            if (Environment.OSVersion.Version.Major < 6)
            {
                return false;
            }
            bool IsGlassSupported = false;
            VistaAPI.DwmIsCompositionEnabled(ref IsGlassSupported);
            return IsGlassSupported;
        }
 
That should cover it. Add that below the constructor.

5) Add this code to the Constructor.

Code: Select all

            if (!this.IsGlassEnabled())
            {
                return;
            }
            marg.Top = <Number of Pixels you want from the top>;
            marg.Bottom = <Number of Pixels you want from the bottom>;
            marg.Left = <Number of Pixels you want from the left>;
            marg.Right = <Number of Pixels you want from the right>;
            VistaAPI.DwmExtendFrameIntoClientArea(this.Handle, ref marg);
  
This is what mine looks like.

Code: Select all

    public partial class Form1 : Form
    {
        //Margins API Call
        private VistaAPI.Margins marg;
        //Creating Glass Rectangle
        private Rectangle toprect = Rectangle.Empty;

        public Form1()
        {
            InitializeComponent();
            if (!this.IsGlassEnabled())
            {
                return;
            }
            marg.Top = 20;
            marg.Bottom = 20;
            marg.Left = 20;
            marg.Right = 20;
            VistaAPI.DwmExtendFrameIntoClientArea(this.Handle, ref marg);
  
        }

        private bool IsGlassEnabled()
        {
            if (Environment.OSVersion.Version.Major < 6)
            {
                return false;
            }
            bool IsGlassSupported = false;
            VistaAPI.DwmIsCompositionEnabled(ref IsGlassSupported);
            return IsGlassSupported;
        }
 
    }
As you can see, I'm extending 20 pixels from each side of the form.

If we are to debug our program now, you will see the border extended, but glass won't show up.

Image

If it shows white where you extended the frame, you are doing everything correct so far!

Now we need to create a paint method. So in the constructor we need to override the OnPaint method.

Just type this.Paint, then press the space bar and press "+" then "=" and press tab twice. It will create the method.

Section 3: Painting the Glass

1) Remove the line of code telling it to throw the exception.
2) Create a new Solid Brush.

Code: Select all

            //Creating a New Solid Black Brush
            SolidBrush BlackBrush = new SolidBrush(Color.Black);
3) Now we need to add a couple of more things.

Code: Select all

            //Creating a New Solid Black Brush
            SolidBrush BlackBrush = new SolidBrush(Color.Black);
            //Referencing Graphics
            Graphics g = e.Graphics;
            //Checking if Glass is enabled
            if (this.IsGlassEnabled())
            {

            }
I will only extend 20 pixels from the top. This is for the sake of demonstration.

4) Add this Inside the If Statement.

Code: Select all

                //Create rectangle to match Glass Area
                toprect =
                    new Rectangle(0, 0, this.ClientSize.Width, marg.Top);
                //Filling the Rectangle with Black Brush
                g.FillRectangle(BlackBrush, toprect);
Now when you debug, it will extend the glass into the non-client area.

Image

Section 4: Moving Window by Clicking on Glass


Congratulations! You can now extend the glass frame as far into the form as you want, But now we need to make it so when you click on the glass, you can move it.

I copied this code from a video, I don't really know how exactly it works, but I understand what it does.

Code: Select all

        #region Dragging the Window
        // make windows do the work for us by lieing to it about where the user clicked
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == VistaAPI.WM_NCHITTEST // if this is a click
                && m.Result.ToInt32() == VistaAPI.HTCLIENT // ...and it is on the client
                && this.IsOnGlass(m.LParam.ToInt32())) // ...and specifically in the glass area
            {
                m.Result = new IntPtr(VistaAPI.HTCAPTION); // lie and say they clicked on the title bar
            }
        }

        private bool IsOnGlass(int lParam)
        {
            if (!this.IsGlassEnabled())
            {
                return false;
            }
            // get screen coordinates
            int x = (lParam << 16) >> 16; // lo order word
            int y = lParam >> 16; // hi order word

            // translate screen coordinates to client area
            Point p = this.PointToClient(new Point(x, y));

            // work out if point clicked is on glass
            if (toprect.Contains(p))
                return true;

            return false;
        }
        #endregion
Now you should be able to move it around on glass.

That concludes how to extend the glass frame into the non client area. In my next tutorial, I will teach you how to draw text on it without any problems.

Right Click and Save or Just go to the URL.
Attachments
GlassTutorial.rar
Demo Project
(37.98 KiB) Downloaded 555 times
Last edited by Click16 on Sun Sep 20, 2009 4:40 pm, edited 1 time in total.
Image
User avatar
Click16
Posts: 1941
Joined: Mon Dec 31, 2007 4:36 am
Location: United States

Re: Extending Aero Glass from Non-Client Area into Client Area

Post by Click16 »

Updated with a Video Link.
Last edited by Click16 on Sun Sep 20, 2009 4:43 pm, edited 1 time in total.
Image
xxpenguinxx
Posts: 1974
Joined: Sun Jan 27, 2008 4:50 am

Re: Extending Aero Glass from Non-Client Area into Client Area

Post by xxpenguinxx »

I normally don't use aero but it is a neat feature for those that do.

Could you post a link to the video the you watched?
DemonicSandwich wrote:See that? You see that how it is highlighted down here but it's not highlighted right there? Ah, I guess that's what I get for pirating it.
In Soviet Russia, DS touches you. Say it again and I'll do more than touch. ~DS -Oh baby
A cat was licking itself to the sound of potato chips.
Post Reply