views:

895

answers:

2

My WinForms application has the standard Aero glass appearance on Vista/Windows 7.

I want to custom draw the window title bar so it retains the Aero glass appearance with the glass min/max/close buttons but without the title text and window icon. I have tried this by overriding WM_NCPAINT but overriding this event always causes the glass to be removed.

Does anyone know how to override WM_NCPAINT with glass in place in order to effectively draw over the glass area correctly?

A: 

See this article. cheers, AR

Alain Rist
This does not implement it using WM_NCPAINT but instead extends the client area.
Phil Wright
+3  A: 

I don't have a solution involving WM_NCPAINT, but I have a solution that does what you want it to do, and perhaps cleaner than the WM_NCPAINT-version would be.

First define this class. You'll use its types and functions to achieve your desired functionality:

internal class NonClientRegionAPI
{
    [DllImport( "DwmApi.dll" )]
    public static extern void DwmIsCompositionEnabled( ref bool pfEnabled );

    [StructLayout( LayoutKind.Sequential )]
    public struct WTA_OPTIONS
    {
        public WTNCA dwFlags;
        public WTNCA dwMask;
    }

    [Flags]
    public enum WTNCA : uint
    {
        NODRAWCAPTION = 1,
        NODRAWICON = 2,
        NOSYSMENU = 4,
        NOMIRRORHELP = 8,
        VALIDBITS = NODRAWCAPTION | NODRAWICON | NOSYSMENU | NOMIRRORHELP
    }

    public enum WINDOWTHEMEATTRIBUTETYPE : uint
    {
        /// <summary>Non-client area window attributes will be set.</summary>
        WTA_NONCLIENT = 1,
    }

    [DllImport( "uxtheme.dll" )]
    public static extern int SetWindowThemeAttribute(
        IntPtr hWnd,
        WINDOWTHEMEATTRIBUTETYPE wtype,
        ref WTA_OPTIONS attributes,
        uint size );
}

Next, in your form, you simply do this:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // Set your options. We want no icon and no caption.
        SetWindowThemeAttributes( NonClientRegionAPI.WTNCA.NODRAWCAPTION | NonClientRegionAPI.WTNCA.NODRAWICON );
    }

    private void SetWindowThemeAttributes( NonClientRegionAPI.WTNCA attributes )
    {
        // This tests that the OS will support what we want to do. Will be false on Windows XP and earlier,
        // as well as on Vista and 7 with Aero Glass disabled.
        bool hasComposition = false;
        NonClientRegionAPI.DwmIsCompositionEnabled( ref hasComposition );
        if( !hasComposition )
            return;

        NonClientRegionAPI.WTA_OPTIONS options = new NonClientRegionAPI.WTA_OPTIONS();
        options.dwFlags = attributes;
        options.dwMask = NonClientRegionAPI.WTNCA.VALIDBITS;

        // The SetWindowThemeAttribute API call takes care of everything
        NonClientRegionAPI.SetWindowThemeAttribute(
            this.Handle,
            NonClientRegionAPI.WINDOWTHEMEATTRIBUTETYPE.WTA_NONCLIENT,
            ref options,
            (uint)Marshal.SizeOf( typeof( NonClientRegionAPI.WTA_OPTIONS ) ) );
    }
}

Here's the result:

I normally make a base class that implements Form with all my funky extended behavior and then let my actual forms implement that base class, but if you only need it for one Form, just put it all in there.

Alex