Search code examples
c#.netwinformswndproc

Winforms - WM_NCHITEST message for click on control


I have a simple windows form with no border and several label controls (nothing that needs to be clicked). I needed to be able to allow the user to move the form by clicking anywhere on it, so I found this question, and used the following code found there.

    private const int WM_NCHITTEST = 0x84;
    private const int HTCLIENT = 0x1;
    private const int HTCAPTION = 0x2;

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg) {
            case WM_NCHITTEST:
                base.WndProc(ref m);

                if ((int)m.Result == HTCLIENT) {
                    m.Result = (IntPtr)HTCAPTION;
                    return;
                } else {
                    return;
                }
                break;
        }
        base.WndProc(ref m);            
    }

This works well...to a point. If I click anywhere on the form itself (the background), WM_NCHITTEST is HTCLIENT, so I can move my form as expected. However, if I click on a label control itself, the message is something different, and I can't tell what it is.

I found this article about the various possible values for WM_NCHITTEST but none of them seem to be what I need.

I realize I could disable all my label controls and that would allow me to click "on" them as if it was the form itself, but I'm wondering if there's a better/different way to do this.

Thanks for the help!


Solution

  • You are overriding the WndProc for the form, but when the cursor is over a label the WM_NCHITTEST message is sent to the label.

    You could create your own label control derived from Label and override its WndProc. This should always return HTTRANSPARENT in response to WM_NCHITTEST. Something like:

    private const int HTTRANSPARENT = -1;
    
    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_NCHITTEST:
                m.Result = (IntPtr)HTTRANSPARENT;
                return;
        }
        base.WndProc(ref m);
    }
    

    Also note that there's a small bug in your WndProc. If the message is WM_NCHITTEST but the region isn't HTCLIENT then you call the base class twice.