Click here to Skip to main content
16,017,954 members
Articles / Programming Languages / C#

Extending the Non Client Area in Aero

Rate me:
Please Sign up or sign in to vote.
4.17/5 (17 votes)
9 Feb 2010CPOL2 min read 69.1K   4.5K   41   17
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:

C#
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:

C#
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.

C#
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).

C#
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)


Written By
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

 
GeneralMy vote of 3 Pin
i0017-Oct-23 18:55
i0017-Oct-23 18:55 
BugWindows 10 issues Pin
rkraen5-Sep-17 2:58
rkraen5-Sep-17 2:58 
GeneralMy vote of 5 Pin
majid torfi2-Nov-14 3:02
professionalmajid torfi2-Nov-14 3:02 
QuestionBest example Pin
gogogoggg16-Feb-13 10:35
professionalgogogoggg16-Feb-13 10:35 
Your example is best I have seen so far. One thing tho, do you know how to fix maximize problem and autohide taskbar ? It seems form goes on top and taskbar is not activated any more.
SuggestionWindows 8 Pin
phatphamhoang4-Aug-12 2:10
phatphamhoang4-Aug-12 2:10 
GeneralRe: Windows 8 Pin
Member 104872091-Jan-15 7:51
Member 104872091-Jan-15 7:51 
GeneralRe: Windows 8 Pin
John Underhill1-Jan-15 8:55
John Underhill1-Jan-15 8:55 
GeneralRe: Windows 8 Pin
hullihulli3-Sep-15 7:45
hullihulli3-Sep-15 7:45 
AnswerRe: Windows 8 Pin
TheFanatr26-Mar-17 18:12
TheFanatr26-Mar-17 18:12 
QuestionMDI Pin
AETCoder30-Jun-11 7:11
AETCoder30-Jun-11 7:11 
GeneralMy vote of 5 Pin
lipinho24-Dec-10 18:27
lipinho24-Dec-10 18:27 
GeneralGreat Article Pin
Scotley18-Oct-10 23:33
Scotley18-Oct-10 23:33 
GeneralFYI wpf Pin
John Underhill13-Apr-10 10:22
John Underhill13-Apr-10 10:22 
GeneralHit-Testing Problematic Pin
ThomasR.29-Jan-10 4:36
ThomasR.29-Jan-10 4:36 
GeneralRe: Hit-Testing Problematic Pin
John Underhill29-Jan-10 5:02
John Underhill29-Jan-10 5:02 
GeneralUpdate coming Pin
John Underhill28-Jan-10 14:47
John Underhill28-Jan-10 14:47 
GeneralRe: Update coming Pin
John Underhill29-Jan-10 9:43
John Underhill29-Jan-10 9:43 

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

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