Untangling the confusingly-named WM_UPDATEUISTATE and WM_CHANGEUISTATE messages

I always get confused by the WM_UPDATE­UI­STATE and WM_CHANGE­UI­STATE messages, and I have to go figure them out each time I need to mess with them. So this time, I'm going to write it down so I don't forget. Because the act of writing it down helps me to remember.

It's like in school, where the teacher says, "This is a closed-book, closed-notes exam, but you are allowed to bring one piece of standard 8½″×11″ paper with you, on which you can write anything you like. No funny business." You work really hard to create the ultimate sheet of paper to bring to the exam, and then it turns out that during the exam, you barely refer to it at all. Because the act of deciding what to put on the cheat sheet made you remember the material.

Part of the problem with the messages WM_UPDATE­UI­STATE and WM_CHANGE­UI­STATE is their confusing names, because to most people update and change are basically the same concept. The difference is the direction the message travels. Before we look at that, let's look at the mysterious WPARAM.

The WPARAM specifies what action you want to perform (initialize, set, or clear) and the target of the action (focus, accelerators, or both).

Action Meaning
UIS_SET Set the flag (hide the indicator).
UIS_CLEAR Clear the flag (show the indicator).
UIS_INITIALIZE Set or clear the flag based on whether the last input event was mouse (set) or keyboard (clear).

Setting a flag hides the corresponding indicator. For example, if you have a UIS_SET for UISF_HIDE­FOCUS, that means that you want to hide focus indicators.

Clearing a flag shows the corresponding indicator. For example, if you have a UIS_CLEAR for UISF_HIDE­FOCUS, that means that you want to show focus indicators.

Yes, it's a bit of a double-negative situation.

Each window has its own internal state that remembers which indicators have been hidden for that window. You can query this state by sending the window a WM_QUERY­UI­STATE message.

The WM_UPDATE­UI­STATE message travels down the tree: When a window receives the WM_UPDATE­UI­STATE message, it updates its state according to the WPARAM and then forwards the message to its children. Therefore, if you want to change the state for an entire window tree, you can send the WM_UPDATE­UI­STATE message to the top-level window, and the message will be delivered to that window and all its children.

It's called update because it says, "Okay, listen up everybody, this is what we're going to do."

The WM_CHANGE­UI­STATE message is more like a change request. It travels up the tree: When a window receives the message, it sees if the state being requested matches the window's current state. If so, then processing stops since there is nothing to change. Otherwise, the window forwards the message to its parent. The idea here is to push the change request up the tree until it finds the top-level window.

If a top-level window receives a WM_CHANGE­UI­STATE message for a state change that actually changes something, it turns around and sends itself a WM_UPDATE­UI­STATE message, which as we saw before, tells the entire window tree to set its indicator state to the value specified.

Okay, let's draw a picture. Suppose we have a top-level window with two children, and suppose that everybody starts out with all indicators hidden.


Window B decides that it wants to show accelerators, say because the user tapped the Alt key. It sends itself a WM_CHANGE­UI­STATE message with a wParam of MAKEWPARAM(UIS_CLEAR, UISF_HIDE­ACCEL).

The WM_CHANGE­UI­STATE message handler for Window B sees that the UISF_HIDE­ACCEL flag is set, so the clear action is meaningful. It forwards the request to its parent, Window A.

The WM_CHANGE­UI­STATE message handler for Window A also sees that the UISF_HIDE­ACCEL flag is set, so the clear action is meaningful. Since it has no parent, Window A converts the WM_CHANGE­UI­STATE message to a WM_UPDATE­UI­STATE message and sends it to itself.

The WM_UPDATE­UI­STATE message handler for Window A sees that it is being told to clear the UISF_HIDE­ACCEL flag, so it clears the flag and then forwards the mesage to both its children.

Each of the child windows B and C receive the WM_UPDATE­UI­STATE message and see that they are also being told to clear the UISF_HIDE­ACCEL flag, so they do so. Those windows have no children of their own, so message processing stops. By this mechanism, Window B has managed to convince all the other windows in the hierarchy to clear the UISF_HIDE­ACCEL flag.


Now, suppose that Window C also decides to clear the accelerator indicator. It does the same thing as Window B and sends itself a WM_CHANGE­UI­STATE message with a wParam of MAKEWPARAM(UIS_CLEAR, UISF_HIDE­ACCEL). This time, the WM_CHANGE­UI­STATE message handler for Window C sees that the UISF_HIDE­ACCEL flag is already clear, so the clear action is redundant. Message processing stops.

These two examples show the flow of the UI state change messages. When somebody wants to suggest a change to the UI state, they send themselves a WM_CHANGE­UI­STATE message with a description of what they want to change. The above algorithm then kicks in to decide whether the change is meaningful, and if so, it notifies all the other windows in the hierarchy about the new state.

Next time, we'll look at how this whole indicator state thing gets off the ground.

Comments (11)
  1. Joshua says:

    For a calculous test, we were allowed one 3×5 card. I filled one side with an integral table. This got on my teacher's nerves when I got a hit on a "show your work" exam and put one step marked table.

  2. jon says:

    Seems a little over-complicated to me :)

    [How would you have made it simpler? -Raymond]
  3. kinokijuf says:

    I can’t imagine what idiot decided that it would be a good idea to hide keyboard cues. Ugh. At least it is not like OSX, where mouse doesn’t set the focus.

    [Randomly underlined letters scream, "This computer is designed for nerds." -Raymond]
  4. jon says:

    I don't know off-hand how I could make it simpler but given that even you're confused by it I'd say it's pretty obvious the design is not as good as it could be.

    Certainly the incredibly lousy documentation doesn't help.

  5. Joshua says:

    @kinokijuf: Change your system settings.

  6. Zan Lynx' says:

    @Mason Wheeler: If you can read your Asian writing. I don't, but I have heard complaints from someone I know that he has to be very precise because if he makes it too small or blurs it he can't tell if it's a right angle or three lines inside a box, etc.

  7. Brian_EE says:

    I remember physics in college (3rd year physics IIRC) we had a prof who allowed one side of one sheet. This being the very early 90's before printers that did anything better than 300 DPI, I took 4 sheets of paper and wrote all my notes in not small, but not large either, handwriting. I then went to the library and used the photocopier to reduce by 50% each sheet, cut and paste the copies together, then photocopy again to a single piece of paper.

    I had the cheat sheet with the most information, and the only complaint was against the inclusion of a diagram showing electron-volt levels, which he tore off the corner of my paper. (He wasn't clear that only formulas and/or text were allowed, I wasn't the only one with a diagram drawn).

    Today, I would create it electronically, of course.

  8. Mason Wheeler says:

    @Joshua: We had a history test one time where the teacher let us use a single index card worth of notes.

    Most students tried to cram as many highlights and key points in as possible. But one guy had a different idea.  He was able to transcribe the entire chapter onto the card… in Japanese.  Asian scripts are *ridiculously* compact.

  9. kinokijuf says:

    Randomly underlined letters scream, "This computer is designed for nerds." -Raymond

    I know several casual users that don’t seem to be bothered by them (I always turn it on on every computer I configure).

  10. Mark S says:

    Speaking of usability, how sad that this blog software is still so terrible at the simple task of taking in and displaying comments.  Is my previous comment submitted once, twice, not at all?  Shrug!

  11. Mark S says:

    Well, appears the answer is "not at all": I had been trying to chime in with kinokijuf but oh well.  (My comment about the blog software was not out of left field; I suspected my comment had been eaten).

Comments are closed.