Click here to Skip to main content
Click here to Skip to main content

Extending the Non Client Area in Aero

, 9 Feb 2010
Rate this:
Please Sign up or sign in to vote.
Demonstrates how to extend the client area into frame or vice versa.
NcRenderer

Introduction

Just a little ToDo for another project, but I thought I'd share some discoveries... Looking at the spec for the DMW API on MSDN, it seemed fairly straightforward, and there is even a nice little article on the subject with some sample code, so I thought... this should only take a couple of minutes.. Well, seven hours later, I finally finished. I only found one other example of this, and that was in Jose Menendez Póo's article Vista Aero ToolStrip on Non-Client Area. Both that implementation and the article on MSDN recommend consuming the WM_NCCALCSIZE message, in effect creating a borderless form, the problem is that if you start resizing the form, after a time, something breaks and the frame turns black. So I went in search of a better solution.

Implementing the intended behavior of extending the Non Client frame in the client area is actually a fairly trivial task. The problem arose when trying to shrink the NonClient, so that I could put some buttons up there, like on Office or MovieMaker. So, I worked with the example provided in the article, to build the basic model, then adjusted the NCCALCSIZE_PARAMS structure to let Windows know the new client area dimensions, something like this:

case WM_NCCALCSIZE:
    {
        if (m.WParam != IntPtr.Zero && m.Result == IntPtr.Zero)
        {
            if (_bExtendIntoFrame)
            {
                _bSizeProcessed = true;
                NCCALCSIZE_PARAMS nc = (NCCALCSIZE_PARAMS)Marshal.PtrToStructure
					(m.LParam, typeof(NCCALCSIZE_PARAMS));
                nc.rect0.Top -= (_tMargins.cyTopHeight > 
			CaptionHeight ? CaptionHeight : _tMargins.cyTopHeight);
                nc.rect1 = nc.rect0;
                Marshal.StructureToPtr(nc, m.LParam, false);
                m.Result = (IntPtr)WVR_VALIDRECTS;
            }
            base.WndProc(ref m);
        }
        else
        {
            base.WndProc(ref m);
        }
        break;
    }

Then, using a PAINTSTRUCT, you simply paint the intended NonClient areas black, which zeroes their alpha values:

case WM_PAINT:
{
    PAINTSTRUCT ps = new PAINTSTRUCT();
    if (!_bPainting)
    {
        _bPainting = true;
        BeginPaint(m.HWnd, ref ps);
        PaintThis(ps.hdc, ps.rcPaint);
        EndPaint(m.HWnd, ref ps);
        _bPainting = false;
        base.WndProc(ref m);
    }
    else
    {
        base.WndProc(ref m);
    }
    break;
}

using (ClippingRegion cp = new ClippingRegion(hdc, clientRect, rc))
{
    if (IsAero())
    {
        FillRect(hdc, ref rc, GetStockObject(BLACK_BRUSH));
...

Lastly, you only need to extend the NonClient area using the DwmExtendFrameIntoClientArea API. This is done when the WM_ACTIVATE message is sent.

The only problem I had left, was that Windows is storing the wrong window size when SC_MAXIMIZE is called, in effect causing the window to grow in height each time the window was restored as per the WM_NCCALCSIZE routine. This was solved by intercepting the SC_RESTORE message through WM_SYSCOMMAND, and setting the proper height.

case WM_SYSCOMMAND:
    {
        UInt32 param;
        if(IntPtr.Size == 4)
             param = (UInt32)(m.WParam.ToInt32());
          else
             param = (UInt32)(m.WParam.ToInt64());
        if ((param & 0xFFF0) == SC_RESTORE)
        {
            this.Height = _iStoreHeight;
        }
        else if (this.WindowState == FormWindowState.Normal)
        {
            _iStoreHeight = this.Height;
        }
        base.WndProc(ref m);
        break;
    }

What We Have Here

To use this code, you only need to copy the contents of the 'Extend Frame' region, update your using directives, and add a single command to the form's class constructor. I cannot make it easier to use than that.

There are three example projects, demonstrating shrinking the Non Client, expanding the Non Client, and a completely transparent window. All of these use the ExtendMargins method. Passing any negative value in will cause the whole form to be transparent. There is also the option to extend into frame, and draw caption (drawn manually when extended into frame).

public Form1()
{
    ExtendMargins(0, 36, 0, 0, true, true);
    SetStyle(ControlStyles.ResizeRedraw, true);
    InitializeComponent();
    DoubleBuffered = true;
}

Updates

  • Posted last update January-30-10, built to work on all frame types

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

John Underhill (Steppenwolfe)
Network Administrator vtdev.com
Canada Canada
Network and programming specialist. Started in C, and have learned about 14 languages since then. Cisco programmer, and lately writing a lot of C# and WPF code, (learning Java too). If I can dream it up, I can probably put it to code. My software company, (VTDev), is on the verge of releasing a couple of very cool things.. keep you posted.

Comments and Discussions

 
QuestionBest example Pinmembergogogoggg16-Feb-13 10:35 
SuggestionWindows 8 Pinmemberphatphamhoang4-Aug-12 2:10 
GeneralRe: Windows 8 Pinmemberjyrka9829-May-14 22:37 
QuestionMDI PinmemberAETCoder30-Jun-11 7:11 
GeneralMy vote of 5 Pinmemberlipinho24-Dec-10 18:27 
GeneralGreat Article PinmemberScotley18-Oct-10 23:33 
GeneralFYI wpf PinmemberSteppenwolfe13-Apr-10 10:22 
GeneralHit-Testing Problematic PinmemberThomasR.29-Jan-10 4:36 
GeneralRe: Hit-Testing Problematic PinmemberSteppenwolfe29-Jan-10 5:02 
GeneralUpdate coming PinmemberSteppenwolfe28-Jan-10 14:47 
GeneralRe: Update coming PinmemberSteppenwolfe29-Jan-10 9:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 9 Feb 2010
Article Copyright 2010 by John Underhill (Steppenwolfe)
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid