1

so I just expanded the glass area of my form into the client area with DwmExtendFrameIntoClientArea (Vista / 7 Aero stuff).

I have already sent a Windows message in the override Form class method OnMouseDown() causing the window to be movable with the glass area, as explained here Make a borderless form movable?.

However because of this, I am not receiving any form Click / MouseClick / DoubleClick etc. events when clicking on the expanded glass area.

I actually want the form to maximize when I double click the top expanded glass area, like normal titlebars do.

Here's the code of the Form-inheriting class:

protected override void OnMouseDown(MouseEventArgs e)
{
    // Fensterverschiebung in Glass-Regionen
    if (_glassMovable && e.Button == MouseButtons.Left
        && (e.X < _glassPadding.Left || e.X > Width - _glassPadding.Right
        || e.Y < _glassPadding.Top || e.Y > Height - _glassPadding.Bottom))
    {
        NativeMethods.ReleaseCapture();
        NativeMethods.SendMessage(Handle, NativeMethods.WM_NCLBUTTONDOWN,
            NativeMethods.HT_CAPTION, 0);
    }

    base.OnMouseDown(e);
}

protected override void OnMouseDoubleClick(MouseEventArgs e)
{
    // Fenstermaximierung / Minimierung in Glass-Regionen
    if (MaximizeBox && e.Button == MouseButtons.Left && e.Y < _glassPadding.Top)
    {
        if (WindowState == FormWindowState.Normal)
        {
            WindowState = FormWindowState.Maximized;
        }
        else if (WindowState == FormWindowState.Maximized)
        {
            WindowState = FormWindowState.Normal;
        }
    }

    base.OnMouseDoubleClick(e);
}

Is there any way to get this to work?

Community
  • 1
  • 1
Ray
  • 7,940
  • 7
  • 58
  • 90
  • You will need to post code. I do know that the event that handles this is connected to the ability to hit the Maximize button. If that is disabled then double click on the titlebar will do nothing, it actually disables the ability for the form to be maximized, at least in the cast of WinForms. – Security Hound Oct 27 '11 at 18:32
  • @Ramhound: Ok, I added the current mouse related code. – Ray Oct 27 '11 at 18:45
  • 2
    You're on the right track sending `HT_CAPTION` messages, but you shouldn't be doing this in a WinForms event handler. The `Form` class has a native `WndProc()` procedure that you should override for your form in order to send `HT_CAPTION`. I can't remember off the bat the exact code, but [I have a similar code sample for WPF](http://stackoverflow.com/questions/5493149/how-do-i-make-a-wpf-window-movable-by-dragging-the-extended-glass-frame). – BoltClock Oct 27 '11 at 18:57
  • You didn't get very good advice from that answer. Type 'wm_nchittest' in the Search box. – Hans Passant Oct 27 '11 at 19:09
  • @BoltClock: Thanks! This helped pretty much. Do you know how I can get the window system menu through right click too? – Ray Oct 28 '11 at 18:14
  • @Pac-Man: That I'm not really sure, sorry :/ – BoltClock Nov 09 '11 at 04:42
  • @BoltClock: I found out how to and added it in the solution below (which I just accepted as an answer) :) – Ray Nov 09 '11 at 12:54

1 Answers1

2

BoltClocks link to a solution for WPF inspired me for the following, similar code for WinForms.

I now override WndProc instead of the OnMouse* events.

The glass region behaves exactly like a title bar, e.g. drag'n'drop with dock support in Windows 7 and double click for maximizing / restoring. Additionally, this solution now supports the system window context menu when right clicking the glass area.

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

private const int WM_NCHITTEST     = 0x0084;
private const int WM_NCRBUTTONDOWN = 0x00A4;
private const int WM_SYSCOMMAND    = 0x0112;
private const int HT_CAPTION       = 0x02;
private const int TPM_RIGHTBUTTON  = 0x0002;
private const int TPM_RETURNCMD    = 0x0100;

[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

[DllImport("user32.dll")]
private static extern int TrackPopupMenu(int hMenu, int wFlags, int x, int y,
    int nReserved, int hwnd, ref RECT lprc);

[DllImport("user32.dll")]
private static extern int PostMessage(int hWnd, int Msg, int wParam,
    int lParam);

protected override void WndProc(ref Message m)
{
    if (!DesignMode)
    {
        switch (m.Msg)
        {
            case WM_NCHITTEST:
                if (MouseInClientArea())
                {
                    if (MouseInGlassArea())
                    {
                        m.Result = (IntPtr)HT_CAPTION;
                    }
                    else
                    {
                        m.Result = IntPtr.Zero;
                    }
                    return;
                }
                break;
            case WM_NCRBUTTONDOWN:
                if (MouseInClientArea())
                {
                    IntPtr menuHandle = GetSystemMenu(Handle, false);
                    RECT rect = new RECT();
                    int menuItem = TrackPopupMenu(menuHandle.ToInt32(),
                        TPM_RIGHTBUTTON | TPM_RETURNCMD,
                        Cursor.Position.X, Cursor.Position.Y, 0,
                        Handle.ToInt32(), ref rect);
                    if (menuItem != 0)
                    {
                        PostMessage(Handle.ToInt32(), WM_SYSCOMMAND,
                            menuItem, 0);
                    }
                }
                break;
        }
    }
    base.WndProc(ref m);
}

private bool MouseInClientArea()
{
    Point p = PointToClient(Cursor.Position);
    return (p.X > 0 && p.X < ClientRectangle.Width
        && p.Y > 0 && p.Y < ClientRectangle.Height);
}

private bool MouseInGlassArea()
{
    if (_glassPadding.Left == -1 || _glassPadding.Right == -1
        || _glassPadding.Top == -1 || _glassPadding.Bottom == -1)
    {
        return true;
    }
    else
    {
        Point p = PointToClient(Cursor.Position);
        return (p.X < _glassPadding.Left
            || p.X > ClientRectangle.Width - _glassPadding.Right
            || p.Y < _glassPadding.Top
            || p.Y > ClientRectangle.Height - _glassPadding.Bottom);
    }
}
Ray
  • 7,940
  • 7
  • 58
  • 90