Reset cursor in WM_SETCURSOR handler properly

Here's my first example, if cursor go to menubar, cursor changes to cursor hand:

HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
    if(LOWORD(lParam) == HTMENU)
    {
          SetCursor(cursorHand);
    }
 break;

Here's my second example, if cursor goes to button, cursor changes to cursorHand:

HCURSOR cursorHand =  LoadCursor(NULL, IDC_HAND);

case WM_SETCURSOR:
      if(LOWORD(lParam) == buttonId)//declare you
      {
            SetCursor(cursorHand);
       }
   break;

Warning:menubar and button is not created! Create you and please, check my answer example.


In general, if you handle the WM_SETCURSOR message you must either

  • Call SetCursor() to set the cursor, and return TRUE, or
  • If the message came from a child window, return FALSE for default processing, or
  • If the message is from your own window, pass the message through to DefWindowProc()

I think the last two points aren't made quite clear by the MSDN docs.

The window under the mouse pointer gets the first WM_SETCURSOR message. If it handles it and returns at that point, nothing else happens. If however it calls DefWindowProc(), then DWP forwards the message to the window's parent to handle. If the parent chooses not to handle it, it can return FALSE and the DefWindowProc processing will continue.

But this only applies if the message came from a previous call to DWP. If the message originated with the window itself, rather than a child, returning TRUE or FALSE without setting the cursor means the cursor won't be set at all.

Another thing: although your question didn't specify, I'm assuming from your use of GetDlgItem() that your top-level window is a dialog. If that's true, you can't just return TRUE or FALSE for a message - you need to return the value using SetWindowLongPtr() and store the return value in DWLP_MSGRESULT. Returning FALSE from a dialog procedure indicates that you didn't handle the message at all - this is equivalent to passing a message through to DefWindowProc().

So I think the proper handling for your situation is, in your top-level window:

case WM_SETCURSOR:
    if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
    {
        SetCursor(hCursorHand); 
        SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
        return TRUE;
    }
    return FALSE;

If your top-level window isn't in fact a dialog, you would do this:

case WM_SETCURSOR:
    if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
    {
        SetCursor(hCursorHand); 
        return TRUE;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);

Tags:

C++

Winapi