2

I want to enable SnapLayout for WPF, because I use Customized Window, according to the documentation, I have to do it myself.

For Win32 apps, make sure you are responding appropriately to WM_NCHITTEST (with a return value of HTMAXBUTTON for the maximize/restore button).

I used the following code

private const int HTMAXBUTTON = 9;
private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam,
    IntPtr lparam, ref bool handled)
{
    switch (msg)
    {
        case InteropValues.WM_NCHITTEST:
        try
        {
            int x = lparam.ToInt32() & 0xffff;
            int y = lparam.ToInt32() >> 16;
            var rect = new Rect(_ButtonMax.PointToScreen(
                new Point()),
                new Size(_ButtonMax.Width, _ButtonMax.Height));
            if (rect.Contains(new Point(x, y)))
            {
                handled = true;
            }
            return new IntPtr(HTMAXBUTTON);
        }
        catch (OverflowException)
        {
            handled = true;
        }
        break;
    }
    return IntPtr.Zero;
}

SnapLayout is displayed well But the maximize button does not work and if I click on it, a button will be created next to it. How can I solve this problem?

Image

Toni
  • 1,555
  • 4
  • 15
  • 23
karma
  • 147
  • 7
  • 1
    Can you provide more code ? The snap layout is not present if you have a "caption buttons or title bar in a way that prevents it", so we need to know how you are preventing it, which may also yield the problem you are posting about. – Soleil Nov 01 '21 at 13:17
  • I have the same issue, but as there is a Button, the Mouse Messages go tho the button and WM_NCHITTEST is not fireed for the form. Can you please post the code for : "Handle various WM_NC* mouse messages and using SendMessage" – user69 Nov 14 '21 at 12:04

1 Answers1

1

Update: This is complete code and works fine (without any issues (mouse hover, click,...))

private const double DPI_SCALE = 1.5;
private const int HTMAXBUTTON = 9;

private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
    switch (msg)
    {
        
        case 0x0084:
            try
            {
                int x = lparam.ToInt32() & 0xffff;
                    int y = lparam.ToInt32() >> 16;
                    Button _button;
                    if (WindowState == WindowState.Maximized)
                    {
                        _button = _ButtonRestore;
                    }
                    else
                    {
                        _button = _ButtonMax;
                    }
                    var rect = new Rect(_button.PointToScreen(
                        new Point()),
                        new Size(_button.Width * DPI_SCALE, _button.Height * DPI_SCALE));
                    if (rect.Contains(new Point(x, y)))
                    {
                        handled = true;
                        _button.Background = OtherButtonHoverBackground;
                    }
                    else
                    {
                        _button.Background = OtherButtonBackground;
                    }
                    return new IntPtr(HTMAXBUTTON);
            }
            catch (OverflowException)
            {
                handled = true;
            }
            break;
        case 0x00A1:
                int x = lparam.ToInt32() & 0xffff;
                int y = lparam.ToInt32() >> 16;
                Button _button;
                if (WindowState == WindowState.Maximized)
                {
                    _button = _ButtonRestore;
                }
                else
                {
                    _button = _ButtonMax;
                }
                var rect = new Rect(_button.PointToScreen(
                    new Point()),
                    new Size(_button.Width * DPI_SCALE, _button.Height * DPI_SCALE));
                if (rect.Contains(new Point(x, y)))
                {
                    handled = true;
                    IInvokeProvider invokeProv = new ButtonAutomationPeer(_button).GetPattern(PatternInterface.Invoke) as IInvokeProvider;
                    invokeProv?.Invoke();
                }
            break;
        default:
            handled = false;
            break;
    }

    return IntPtr.Zero;
}

you need to define OtherButtonHoverBackground and OtherButtonBackground or replace with SolidColorBrush.

Katana
  • 752
  • 4
  • 23
  • Your method of getting the X value didn't work for me. It returned some value that was very incorrect. Here's what did work: var x = (short)(((uint)lParam.ToInt64()) & 0xffff); var y = (short)((((uint)lParam.ToInt64()) >> 16) & 0xffff); – SonofNun May 25 '22 at 17:28
  • Also, this solution only works for me if my window is maximized. If it is minimized, the "Snap Layout" popup doesn't open. I'm not sure why. – SonofNun May 25 '22 at 17:29