Use WM_WINDOWPOSCHANGING to intercept window state changes


The WM_WINDOWPOSCHANGING message is sent early in the window state changing process, unlike WM_WINDOWPOSCHANGED, which tells you about what already happened. A crucial difference (aside from the timing) is that you can influence the state change by handling the WM_WINDOWPOSCHANGING message and modifying the WINDOWPOS structure.

Here's an example that prevents the window from being resized.

BOOL OnWindowPosChanging(HWND hwnd, WINDOWPOS *pwp)
{
    pwp->flags |= SWP_NOSIZE;
    /* Continue with default handling */
    return FORWARD_WM_WINDOWPOSCHANGING(hwnd, pwp, DefWindowProc);
}

HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, OnWindowPosChanging);

Before the WM_WINDOWPOSCHANGING message was invented, programs had to enforce window size constraints inside their WM_SIZE and WM_MOVE handlers, but since those messages are sent after the change is complete, the result was flicker as the window changed to one size, then the WM_SIZE handler resized it to a better size. Intercepting the window size change in WM_WINDOWPOSCHANGING allows you to enforce constraints before the sizing happens, thereby avoiding flicker.

The WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED pair of messages is just one example of the more general *CHANGING/*CHANGED pattern. (Other examples are WM_STYLECHANGING/WM_STYLECHANGED and LVN_ITEMCHANGING/LVN_ITEMCHANGED.) The *CHANGING half is sent before the change takes place, and as a general rule, you can change the parameters of the notification to enforce some type of constraint. After you return from the *CHANGING notification, the actual change takes place, and then you receive a *CHANGED to indicate that the change is complete.

Comments (5)
  1. nathan_works says:

    That pattern is also used in a number of other MSFT products, such as Sharepoint, if you want event notifications. Useful if, as mentioned, you want to cancel an operation in progress or before it is ‘committed’.

  2. Adrian says:

    Interesting.  In the rare instances where I’ve need to control a size change, I’ve responded to WM_GETMINMAXINFO by setting the min and max tracking sizes to the current size.  Does that pre-date the WM_WINDOWPOSCHANGING message as well?  Are the WM_SIZING and WM_MOVING messages synthesized when the WM_WINDOWPOSCHANGING message goes to the DefaultWinProc?

  3. toomuchwin32 says:

    Adrian:

    WM_SIZING and WM_MOVING are only sent from the message loop that hancles resizing or moving by the end-user (i.e. when the end-user grabs a corner of the window and resizes). They are not sent when a window’s position is changed using the SetWindowPos API.

    One thing to remember is that the SWP_NOSENDCHANGING flag can be used in the SetWindowPos API to prevent the WM_WINDOWPOSCHANGING message from being generated.

  4. Dustin Long says:

    That’s pretty cool. Reminds me of the before/after pattern seen in clos / aspect orientated programming. A very useful pattern, indeed.

  5. iain says:

    And don’t forget the value of the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages. Useful if your window contents are dependent on window size but expensive to compute, as they give you a way to defer paints until the end of the resize action. We found WM_WINDOWPOSCHANGING/ED wasn’t reliable for that purpose.

Comments are closed.

Skip to main content