3

I've been trying to get a Form Border (title bar) mouse up for a bit now, and it seems like it's broken (I have found numerous other articles that state the same).

I have tested:

Const WM_LBUTTONUP = &H202
Const WM_MBUTTONUP = &H208
Const WM_RBUTTONUP = &H205
Const WM_NCXBUTTONUP = &HAC
Const WM_XBUTTONUP = &H20C
Const WM_MENURBUTTONUP = &H122
Const WM_NCLBUTTONUP = &HA2
Const WM_NCRBUTTONUP = &HA5
Const WM_NCLBUTTONDOWN = &HA1
Const WM_NCMOUSEMOVE = &HA0

quite thoroughly. What I am seeing is that, while WM_NCLBUTTONUP doesn't work, WM_NCLBUTTONDOWN does, and upon release (where I would expect the WM_NCLBUTTONUP), I get a WM_NCMOUSEMOVE instead. The issue being that you also get a WM_NCMOUSEMOVE as expected whenever you move the mouse outside of the client area (aka the form border)..

In a first attempt to overcome this, I have come up with:

Private MouseIsDown As Boolean = False
Protected Overrides Sub WndProc(ByRef m As Message)
    Const WM_NCLBUTTONDOWN = &HA1
    Const WM_NCMOUSEMOVE = &HA0
    If (m.Msg = WM_NCLBUTTONDOWN) Then
        MouseIsDown = True
        Console.WriteLine("NCLButtonDown")
    ElseIf (m.Msg = WM_NCMOUSEMOVE) Then
        If MouseIsDown Then
            Console.WriteLine("NCMouseMove" + Environment.NewLine + "LParam: " + m.LParam.ToString() + Environment.NewLine + "WParam: " + m.WParam.ToString() + Environment.NewLine + "Res: " + m.Result.ToString())
            MouseIsDown = False
        Else
            Console.WriteLine("Not mouseup")
        End If
    Else
    End If
    MyBase.WndProc(m)
End Sub

This seems to be working through initial testing, but I am curious if this would be appropriate, or if there is a message that I am simply missing (I have looked through: http://www.pinvoke.net/default.aspx/Constants.WM quite closely though, and don't see anything else that looks right).

Aaron
  • 1,313
  • 16
  • 26
  • 5
    When I attempt this, I get the following messages: WM_NCLBUTTONDOWN [161] WM_SYSCOMMAND [274] WM_CAPTURECHANGED [533] According to the docs for NCLBUTTONUP: _If a window has captured the mouse, this message is not posted._ Perhaps by virtue of clicking the button, the window captures the mouse? Just a guess. – Chris Dunaway Jun 02 '17 at 21:09

1 Answers1

0

You can use a NativeWindow or call WndProc on Form intance Code Translator | VB WindowsMessages

Try this:

    private NativeWnd _nativeWnd;

    private void Form1_Load(object sender, EventArgs e)
    {
        _nativeWnd = new NativeWnd(this);
    }

    class NativeWnd : NativeWindow, IDisposable
    {
        public NativeWnd(Form owner)
        {
            base.AssignHandle(owner.Handle);
        }

        private enum WindowMessages
        {
            // non client mouse
            WM_NCMOUSEMOVE = 0x00A0,
            WM_NCLBUTTONDOWN = 0x00A1,
            WM_NCLBUTTONUP = 0x00A2,
            WM_NCLBUTTONDBLCLK = 0x00A3,
            WM_NCRBUTTONDOWN = 0x00A4,
            WM_NCRBUTTONUP = 0x00A5,
            WM_NCRBUTTONDBLCLK = 0x00A6,
            WM_NCMBUTTONDOWN = 0x00A7,
            WM_NCMBUTTONUP = 0x00A8,
            WM_NCMBUTTONDBLCLK = 0x00A9,
        }


        private bool MouseIsDown;
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                //Mouse Down
                case (int)WindowMessages.WM_NCLBUTTONDOWN:
                case (int)WindowMessages.WM_NCRBUTTONDOWN:
                case (int)WindowMessages.WM_NCMBUTTONDOWN:
                    MouseIsDown = true;
                    Debug.Write("NCMouseDown");
                    break;
                //MouseMove
                case (int)WindowMessages.WM_NCMOUSEMOVE:

                    if (MouseIsDown)
                    {
                        Debug.Write("NCMouseMove");
                        MouseIsDown = false;
                    }
                    break;
                //Mouse Up
                case (int)WindowMessages.WM_NCRBUTTONUP:
                case (int)WindowMessages.WM_NCLBUTTONUP:
                case (int)WindowMessages.WM_NCMBUTTONUP:
                    Debug.Write("NCMouseUp");
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        #region IDisposable 

        public void Dispose()
        {
            base.ReleaseHandle();
        }

        #endregion
    }
Karloz Rivas
  • 1
  • 1
  • 2
  • I don't see how this is going to help him solve the problem. Have you tested this and verified that it is working? Becase according to the OP `WM_NCLBUTTONUP` doesn't work. – Visual Vincent Jun 02 '17 at 23:40
  • Sure, I've tried it. The `WM_LBUTTONUP` does not work because `WM_NCLBUTTONDOWN` call **DefWndProc ()** method as default, here is the code: [link](https://1drv.ms/u/s!AphqixWU563eiiBc7sduu-JlcSnU) – Karloz Rivas Jun 03 '17 at 14:27
  • Did you mean `WM_NCLBUTTONUP`? Because that's what the OP is having problems with, and if it doesn't work in your code then this doesn't answer his question (I am in no position to test it, so that's why I'm writing this comment). – Visual Vincent Jun 03 '17 at 18:21