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