'How to support snap layout in WinForms in C# for windows 11

How to support snap layout in WinForms for windows 11. I'm using c# 10.

enter image description here

My application's custom maximize button shows only tooltip.

MainForm's WndProc code:

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_NCHITTEST:
            base.WndProc(ref m);
            if (WindowState == FormWindowState.Normal && m.Result == (IntPtr)HitTestValues.HTCLIENT)
                m.Result = (IntPtr)(PointToClient(new(m.LParam.ToInt32())) switch
                {
                    var v when v.Y <= resizeAreaSize && v.X <= resizeAreaSize                  => HitTestValues.HTTOPLEFT,
                    var v when v.Y <= resizeAreaSize && v.X < Width - resizeAreaSize           => HitTestValues.HTTOP,
                    var v when v.Y <= resizeAreaSize                                           => HitTestValues.HTTOPRIGHT,
                    var v when v.Y <= Height - resizeAreaSize && v.X <= resizeAreaSize         => HitTestValues.HTLEFT,
                    var v when v.Y <= Height - resizeAreaSize && v.X > Width - resizeAreaSize  => HitTestValues.HTRIGHT,
                    var v when v.Y <= Height - resizeAreaSize                                  => (HitTestValues)m.Result,
                    var v when v.X <= resizeAreaSize                                           => HitTestValues.HTBOTTOMLEFT,
                    var v when v.X <= Width - resizeAreaSize                                   => HitTestValues.HTBOTTOM,
                    _                                                                          => HitTestValues.HTBOTTOMRIGHT,
                });
            return;
        case WM_NCCALCSIZE:
            return;
        case WM_SYSCOMMAND:
            (formSize, Size) = (m.WParam.ToInt32() & 0xFFF0) switch
            {
                SC_MINIMIZE => (ClientSize, Size),
                SC_RESTORE  => (formSize, formSize),
                _           => (formSize, Size),
            };
            (m.WParam.ToInt32() switch
            {
                MY_FULLSCREENMENU     => fullScreenToolStripMenuItem_Click,
                MY_COMPACTOVERLAYMENU => compactToolStripMenuItem_Click,
                _                     => (Action<object, EventArgs>)((s, e) => {})
            })(null, null);
            break;
    }
    base.WndProc(ref m);
    Console.WriteLine(m.ToString());
}

Constant int value:

private const int WM_NCCALCSIZE = 0x0083;
private const int WM_SYSCOMMAND = 0x0112;
private const int WM_POPUPSYSTEMMENU = 0x313;
private const int WM_MOUSEMOVE = 0x0200;
private const int WM_NCHITTEST = 0x0084;
private const int WS_SYSMENU = 0x80000;
private const int WS_MINIMIZEBOX = 0x20000;
private const int WS_MAXIMIZEBOX = 0x10000;
private const int SC_MINIMIZE = 0xF020;
private const int SC_RESTORE = 0xF120;
private const int resizeAreaSize = 10;
public const int MY_FULLSCREENMENU = 1020202020;
public const int MY_COMPACTOVERLAYMENU = 1001303000;
public const int MF_BYPOSITION = 0x400;
public const int MF_SEPARATOR = 0x800;

And HitTestValue enum of c# is on this link.

I want to support the snap layout on my maximize button. max button variable's name is maxbtn.

I didn't find any snap layout for WinForms. It only give me results for UWP (Universal Windows Platform) and WPF (Windows Presentation Foundation).



Solution 1:[1]

An ugly implementation is to call WIN+Z when your mouse moves over the maximized button control. On my Custom Form, I've implemented it with 2 timers one for calling the snaplayout (0.4 secs) and another one to dismiss it after 4 secs (checking if it's already displayed, and ....).

To Call the WIN+Z I use:

    private void SendWinZ()
    {
        //send Win+Z
        KeyboardSend.KeyDown(Keys.LWin);
        KeyboardSend.KeyDown(Keys.Z);
        KeyboardSend.KeyUp(Keys.LWin);
        KeyboardSend.KeyUp(Keys.Z);
    }

Where KeybordSend is:

public static class KeyboardSend
{
    [DllImport("user32.dll")]
    private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

    private const int KEYEVENTF_EXTENDEDKEY = 1;
    private const int KEYEVENTF_KEYUP = 2;

    public static void KeyDown(Keys vKey)
    {
        keybd_event((byte)vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
    }

    public static void KeyUp(Keys vKey)
    {
        keybd_event((byte)vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    }
}

The result with my custom form and controls is this: enter image description here

As I said, it's not a "clean solution" but, for the time being, it's working ... Angelo

Solution 2:[2]

I've digged a bit into this, and you can check here for some documentation: https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/apply-snap-layout-menu

You have to override WndProc on your custom button allowing it to respond appropriately to WM_NCHITTEST?(with a return value of HTMAXBUTTON for the?maximize/restore button).

you can try something like this:

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == (int)WinApi.WM_NCHITTEST && buttonType == WindowButtons.Maximize)
        {
            m.Result = new IntPtr((int)WinApi.HitTest.HTMAXBUTTON);
        }
        else
        {
            base.WndProc(ref m);
        }
    }

with WinApi.WM_NCHITTEST:

public const int WM_NCHITTEST = 0x84;

and WinApi.HitTest:

    public enum HitTest
    {
        HTNOWHERE = 0,
        HTCLIENT = 1,
        HTCAPTION = 2,
        HTGROWBOX = 4,
        HTSIZE = HTGROWBOX,
        HTMINBUTTON = 8,
        HTMAXBUTTON = 9,
        HTLEFT = 10,
        HTRIGHT = 11,
        HTTOP = 12,
        HTTOPLEFT = 13,
        HTTOPRIGHT = 14,
        HTBOTTOM = 15,
        HTBOTTOMLEFT = 16,
        HTBOTTOMRIGHT = 17,
        HTREDUCE = HTMINBUTTON,
        HTZOOM = HTMAXBUTTON,
        HTSIZEFIRST = HTLEFT,
        HTSIZELAST = HTBOTTOMRIGHT,
        HTTRANSPARENT = -1
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Angelo Cresta