The dangers of playing focus games when handling a WM_KILLFOCUS message

I had noted last year that WM_KILLFOCUS is the wrong time to do field validation. Here's another example of how messing with the focus during a WM_KILLFOCUS message can create confusion.

Consider an edit control that displays feedback via a balloon tip. For example, password edit controls often warn you if you're typing your password while CapsLock is in effect. One of the things you probably want to do is to remove the balloon tip if the user moves focus to another control, since there's no point telling the user about a problem with something they aren't using. You might be tempted to subclass the edit control and do something like this:

    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  switch (uMsg) {
    if (hwndBalloonTip) {
      hwndBalloonTip = NULL;
  return CallWindowProc(prevWndProc, hwnd, uMsg, wParam, lParam);

When you give this code a shot, it works great... unless the user clicks on the balloon tip itself the edit control's caret (the blinking insertion point thingie) disappears. What happened?

What happened is that you gummed up the focus change process by destroying the window that focus was going to! The focus change process goes like this:

  • Put focus on new focus window.
  • Send WM_KILLFOCUS to old focus window (if any).
  • Send WM_SETFOCUS to new focus window (if any).

But in the second step, we destroyed the new focus window. When the focus window is destroyed, the window manager tries to find a new focus window, and it settles upon the edit control itself. This starts a recursive focus change cycle, telling the edit control that it now has focus again.

Let's look at the flow in this nested focus change scenario when the user clicks on the tooltip window.

  • Put focus on tooltip.
  • Send WM_KILLFOCUS to edit control.
    • EditSubclass destroys the tooltip.
      • Window manager puts focus on the edit control.
      • Nobody to send WM_KILLFOCUS to.
      • Send WM_SETFOCUS to edit control.
        • EditSubclass passes WM_SETFOCUS to the original window procedure.
    • EditSubclass passes WM_KILLFOCUS to the original window procedure.
  • Send WM_SETFOCUS to tooltip - fails (tooltip was destroyed).

Do you see the problem yet?

Look at the message traffic as it reaches the original edit control window procedure:

  • WM_SETFOCUS (from the nested focus change)
  • WM_KILLFOCUS (from the original focus change)

As far as the edit control is concerned, it gained focus then lost it. Therefore, no caret, since the edit control displays a caret only when it has focus, and your recursive focus changing has resulted in the edit control thinking it doesn't have focus even though it does.

There are many ways out of this mess.

First, notice that you don't need to subclass the edit control; you can just react to the EN_KILLFOCUS notification. Second, you can respond to the EN_KILLFOCUS by posting yourself a message and destroying the tooltip on receipt of that posted message. By doing it via a posted message, you avoid the recursive focus change since your work is now being done outside a focus change cycle.

Comments (8)
  1. hey says:

    But its OK to using WM_KILLFOCUS if you aren’t creating any windows, right?

  2. Please read the linked article "WM_KILLFOCUS is the wrong time to do validation".

  3. waleri says:

    Basicaly, the problem is that EditSubclass first destroys tooltip, then pass WM_KILLFOCUS to original edit proc. Should it first send WM_KILLFOCUS to the edit window, things will work fine

  4. TC says:

    It amazes me that these things still cause problems at this stage of win32 development.

    Surely there’s a big list somewhere, that says: "If you want to achieve result ‘A’, write code ‘X’; if you want to achieve result ‘B’, write code ‘Y’", and so on?

    I don’t do win32 UI directly using the APIs, so I can’t answer that question. But if I started to do it, I’d sure be looking for that list! Why try re-inventing the wheel?


  5. carlso says:

    There’s no need to create a user-defined message in order to do a PostMessage so that you can destroy the window outside of the focus processing cycle. Just use WM_CLOSE.

    For example:

    case WM_KILLFOCUS:

    if (hwndBalloonTip) {

    PostMessage(hwndBalloonTip, WM_CLOSE, 0, 0);

    hwndBalloonTip = NULL;



  6. Bryan says:

    If the tooltip balloon window is owned by a different thread, wouldn’t you have a race between the posted message being handled and your window procedure finishing? If the posted message wins, you might have the same problem.

    That may not even be an issue, though.

  7. It gums up the activation system.

  8. Koro says:

    What is the window you destroy in WM_KILLFOCUS handles WM_MOUSEACTIVATE by returning MA_NOACTIVATE?

Comments are closed.