Search code examples
c#winformswndproc

WM_LBUTTONDOWN and WM_LBUTTONUP messages are not received in the WndProc for filled rectangles


I have made a semi-transparent, borderless form with a resizable transparent panel in the middle. To do this, overriding the OnPaint, I painted dashed borders and boxes around the panel using e.Graphics.DrawLines(...), e.Graphics.FillRectangles(...), and e.Graphics.DrawRectangles(...) methods. I then handled the WM_NCHITTEST and WM_MOUSEMOVE in the WndProc as below.

protected override void WndProc(ref Message m)
{
    bool handled = false;

    if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
    {
        if (...) // any of the boxes contains the client-point
        {
            m.Result = (IntPtr)HT; // HT can be HTLEFT = 10, HTRIGHT = 11, and so on
            handled = true;
        }
    }

    if (!handled)
        base.WndProc(ref m);
}

The resizable transparent panel in the middle of a semi-transparent borderless form

So far so good—the dashed borders and the boxes filled with a white brush pass the hit test successfully. Now, I also need to handle the WM_LBUTTONDOWN and WM_LBUTTONUP messages in the WndProc. It seems the WndProc receives either of these messages only when the pointer is over the borders of the panel (i.e., drawn with the e.Graphics.DrawLines(...)) or the borders of the boxes (i.e., drawn with the e.Graphics.DrawRectangles(...)) but not when the mouse pointer is over the filled area of the boxes (i.e., filled with the e.Graphics.FilledRectangles(...)). Any suggestions as to why this is happening?

protected override void WndProc(ref Message m)
{
    bool handled = false;

    if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONUP)
    {
        // unreachable for the filled rectangles!?
    }

    if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
    {
        ...
    }

    if (!handled)
        base.WndProc(ref m);
}

UPDATE

Inspired by @l33t, I added the following line to the WndProc to monitor all messages.

Debug.WriteLine($"m.Msg = {m.Msg}");

Here is the list of all the messages received.

const uint WM_SIZE = 0x0005;                // 5  
const uint WM_GETTEXT = 0x000d;             // 13 
const uint WM_GETTEXTLENGTH = 0x000e;       // 14 
const uint WM_PAINT = 0x000f;               // 15 
const uint WM_ERASEBKGND = 0x0014;          // 20 
const uint WM_SETCURSOR = 0x0020;           // 32 
const uint WM_MOUSEACTIVATE = 0x0021;       // 33 
const uint WM_CHILDACTIVATE = 0x0022;       // 34 
const uint WM_GETMINMAXINFO = 0x0024;       // 36 
const uint WM_WINDOWPOSCHANGING = 0x0046;   // 70 
const uint WM_WINDOWPOSCHANGED = 0x0047;    // 71 
const uint WM_NCCALCSIZE = 0x0083;          // 131
const uint WM_NCHITTEST = 0x0084;           // 132
const uint WM_NCPAINT = 0x0085;             // 133
const uint WM_NCMOUSEMOVE = 0x00a0;         // 160
const uint WM_NCLBUTTONDOWN = 0x00a1;       // 161
const uint WM_NCLBUTTONUP = 0x00a2;         // 162
const uint WM_NCLBUTTONDBLCLK = 0x00a3;     // 163
const uint WM_NCRBUTTONDOWN = 0x00a4;       // 164
const uint WM_NCRBUTTONUP = 0x00a5;         // 165
const uint WM_NCRBUTTONDBLCLK = 0x00a6;     // 166
const uint WM_NCMBUTTONDOWN = 0x00a7;       // 167
const uint WM_NCMBUTTONUP = 0x00a8;         // 168
const uint WM_NCMBUTTONDBLCLK = 0x00a9;     // 169
const uint WM_NCXBUTTONDOWN = 0x00ab;       // 171
const uint WM_NCXBUTTONUP = 0x00ac;         // 172
const uint WM_NCXBUTTONDBLCLK = 0x00ad;     // 173
const uint WM_COMMAND = 0x0111;             // 273
const uint WM_SYSCOMMAND = 0x0112;          // 274
const uint WM_MOUSEMOVE = 0x0200;           // 512     
const uint WM_NEXTMENU = 0x0213;            // 531
const uint WM_SIZING = 0x0214;              // 532
const uint WM_CAPTURECHANGED = 0x0215;      // 533
const uint WM_ENTERSIZEMOVE = 0x0231;       // 561
const uint WM_EXITSIZEMOVE = 0x0232;        // 562

It turned out that WM_NCLBUTTONUP was not received either. I found the WM_EXITSIZEMOVE being received at the end of any operations on the drawn objects.


Solution

  • Wild guess; try WM_NCLBUTTONDOWN and WM_NCLBUTTONUP instead.

    If that doesn't help, try running Spy++ to see which mouse messages are in fact sent. Also, handling mouse messages that do not belong to your own window (i.e. the Desktop) requires a mouse hook.