0

I am having the Problem, that if I alter the LParam of a WM_MOVING message to keep my Form at a certain position, which is legal according to this , the Windows Aero Shake feature gets triggered and all other Windows minimize. The behaviour can be reproduced by creating a Windows Forms Project in Visual Studio and pasting the following code into the Form:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace FormsTest
{
    public partial class ShakeTest : Form
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        public const int WM_MOVING = 0x0216;

        public ShakeTest()
        {
            InitializeComponent();
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {

                case WM_MOVING:
                    {
                        RECT rec;
                        rec.bottom = 500;
                        rec.left = 100;
                        rec.top = 100;
                        rec.right = 500;

                        Marshal.StructureToPtr(rec, m.LParam, true);

                        m.Result = new IntPtr(1);
                    }

                    break;
            }

            base.WndProc(ref m);
        }
    }
}

If you now grab the Window's title bar and move the mouse around a bit, the Shake gesture should get triggered, even though the Window isn't moving at all.

I tested this on Windows 10 only so far.

So my question is, can i disable the Shake feature for a certain Window or Process? If not, can i prevent Windows from thinking that im shaking the Window any other Way?

Thanks!

Robert
  • 1
  • 1
  • No, this is not about stopping the user from maximizing the form, the example is just very simplified, what im really doing is snapping the window to certain "Dock Areas" – Robert Apr 26 '18 at 11:25
  • The comment i responded to just magially dissappeared – Robert Apr 26 '18 at 11:27
  • Check this: https://stackoverflow.com/questions/907830/how-do-you-prevent-a-windows-from-being-moved – Sergey Shevchenko Apr 26 '18 at 15:48
  • @SergeyShevchenko That doesnt work for my case because it only fires once when the move starts, what i need is to alter the bounds of the window whilst moving – Robert Apr 26 '18 at 22:15
  • Ok, I just compiled your code and saw that the window stays at the same position all the time so I decided - that is what you want to achieve. I'll get back with another example... – Sergey Shevchenko Apr 27 '18 at 10:33

1 Answers1

0

Frankly, I don't know if that is possible to disable Aero Shake for a particular window. But I can suggest a workaround that will prevent the Aero Shake from triggering.

There's a possibility to direct all the mouse input to only one window (and this will also hide the mouse events from the Aero Shake handler). Check the SetCapture description at MSDN. Also we will need a GetCapture and ReleaseCapture functions.

There's one remark: once you have set the mouse capture to a window - you are responsible for handling all the mouse input. So to achieve the goal you'll need to implement your own handler that will move the window. Fortunately, it's not that difficult.

Here's a code sample with a dialog that changes its size when it gets moving and restores the size when the moving is finished. Aero Shake is also never triggered.

public partial class ShakeTest : Form
{
    [DllImport("user32.dll")]
    static extern IntPtr SetCapture(IntPtr hWnd);
    [DllImport("user32.dll")]
    static extern IntPtr GetCapture();
    [DllImport("user32.dll")]
    static extern bool ReleaseCapture();

    public const int WM_LBUTTONUP = 0x0202;
    public const int WM_MOUSEMOVE = 0x0200;
    public const int WM_NCLBUTTONDOWN = 0x00A1;
    public const int HTCAPTION = 2;

    private Point _lastCursorPos;
    private Size _origianlSize;

    public ShakeTest()
    {
        InitializeComponent();
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {

            // We need to get the moment when the user clicked on a non-client area
            case WM_NCLBUTTONDOWN:
                // We are interested only in a click on a title bar
                if ((int) m.WParam == HTCAPTION)
                {
                    // Set the capture so all the mouse input will be handled by this window
                    SetCapture(Handle);

                    // Keep the current cursor position to use it during the moving.
                    _lastCursorPos = Cursor.Position;

                    // Keep the original window size.
                    _origianlSize = Size;

                    // And change the dialog size to whatever you want
                    Size = new Size(300, 300);
                }
                break;

            // Once we got the capture, we need to handle mouse moving by ourself
            case WM_MOUSEMOVE:

                // Check that our window has the capture
                if (GetCapture() == Handle)
                {
                    // Change the position of a window
                    Left += Cursor.Position.X - _lastCursorPos.X;
                    Top += Cursor.Position.Y - _lastCursorPos.Y;

                    _lastCursorPos = Cursor.Position;
                }
                break;

            // When the left mouse button is released - it's time to release the mouse capture
            case WM_LBUTTONUP:

                // Check that our window has the capture
                if (GetCapture() == Handle)
                {
                    // Release the mouse capture
                    ReleaseCapture();

                    // Restore the size
                    Size = _origianlSize;
                }
                break;
        }

        base.WndProc(ref m);
    }
}