The effect of SetCursor lasts only until the next SetCursor

Date:May 25, 2005 / year-entry #129
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20050525-27/?p=35543
Comments:    8
Summary:Of course the effect of the SetCursor function for a thread lasts only until that thread changes the cursor to something else. Any moron knows that, right? The tricky part is that the SetCursor may come from an unexpected place. THe most common place people run into this is when they do something like this:...

Of course the effect of the SetCursor function for a thread lasts only until that thread changes the cursor to something else. Any moron knows that, right?

The tricky part is that the SetCursor may come from an unexpected place.

THe most common place people run into this is when they do something like this:

// Put up the hourglass
HCURSOR hcurPrev = SetCursor(hcurWait);
... do some processing ...
// Restore the original cursor
SetCursor(hcurPrev);

This puts up the hourglass during the processing. But if you pump messages (or if a function you call pumps messages), then the hourglass will go away and return to the normal arrow.

That's because when you pump messages, this opens the gates for messages like WM_NCHITTEST and WM_SETCURSOR. The latter in particular will typically result in the cursor changing, either to a cursor selected by the window itself or to the class cursor if the message makes it all the way to DefWindowProc.

If you want to keep the hourglass up even while pumping messages, you need to let the window know that "If you are asked to set the cursor, please put up an hourglass instead of what you would normally display as the cursor." That window would then have to alter its WM_SETCURSOR handling to take this setting into account.

case WM_SETCURSOR:
 if (ForceHourglass()) {
   SetCursor(hcurWait);
   return TRUE;
 }
 ...

Note that forcing the hourglass is only the tip of the iceberg. Even though the cursor is an hourglass, the window is still active and can receive other message, such as mouse clicks and keypresses. If your program is not ready to receive new input during this phase, you need to detect this case and not go into some recursive state if the user, say, impatiently clicks the "Compute!" button while you are still computing.


Comments (8)
  1. What about calling SetClassLongPtr() with the GCLP_HCURSOR param. Is this an acceptable alternative, or does this have issues of it’s own?

  2. Simon Cooke says:

    I spy, with my little eye, an upcoming mini-series of articles on modal loops, message pumps, and potentially message filters.

    ;-)

  3. Universalis says:

    That’s why OLE doesn’t work. Your application can be all innocently repainting its window in WM_PAINT, including asking OLE to paint any embedded objects that may be lying around… but while it’s waiting in a message pump for that repaint to finish, anything can happen.

    Including the entire window getting resized because the user has just pressed Alt+L to lock his computer. And of course your paint routine knew things like that wouldn’t happen, didn’t it? And of course it calculated and saved the window size and so on, to save time, didn’t it?

  4. ChrisV says:

    Does this apply to ShowCursor as well? I’ve noticed that the cursor, once hidden, tends to reappear if my app changes video modes for our head-mounted display. (Since we use OpenGL rather than Direct3D, it’s a hack involving ChangeDisplaySettingsEx, ShowCursor, and some window resizing.)

  5. ChrisV says:

    Never mind. Adding a WM_SETCURSOR handler seemed to clear everything up.

  6. It’s obvious yet not obvious enough.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index