Microsoft KB Archive/71197

From BetaArchive Wiki

INF: Do Not Call WinSetFocus() On Certain WM_* Messages PSS ID Number: Q71197 Article last modified on 09-09-1991 PSS database name: P_PresMan

1.21 1.30

OS/2

Summary:

An application should not call WinSetFocus() on any of the following messages: WM_FOCUSCHANGE, WM_ACTIVATE, WM_SETSELECTION, and WM_SETFOCUS. The following information describes why it is not appropriate to do this.

An application program should never post or send any of these four messages itself. Based on this restriction, the only time these messages can occur is in the context of a call to WinSetFocus(). WinSetFocus() is the API that causes these messages to be sent. If WinSetFocus() is called on one of these messages, the thread would be reentering the function. However, the WinSetFocus() code is protected by an internal semaphore to prevent this from happening. WinSetFocus() will simply return false if the application attempts to do this.

The WM_FOCUSCHANGE message is qualitatively different from the other three messages. WM_ACTIVATE, WM_SETSELECTION, and WM_SETFOCUS are notification messages that inform a window of how it should be painted. In fact, WM_SETSELECTION and WM_SETFOCUS are sent only to the single window gaining the focus and the single window losing it. They do not get passed up or down the window tree.

The WinSetFocus() function sends the WM_FOCUSCHANGE message two times: once to the window losing the focus, and once to the window getting the focus. The behavior of WinDefWindowProc() is to send this message up the focus chain (that is, to the owner, when present; otherwise, it is sent to the parent). The message is thus passed up the window chain until it gets to the first frame window (usually one or two steps). The default behavior for the frame-window window procedure is to send out the WM_ACTIVATE, WM_SETSELECTION, and WM_SETFOCUS messages conditional on the bits in SHORT2FROMMP (mp2) (for example, the FC_NO flags). After all of this happens, the frame window continues to send the WM_FOCUSCHANGE message on up the focus chain. However, at this point, the focus ORs in all of the FC_NO flags so that future frame windows do not also send these messages.

In summary, the call to WinSetFocus() causes the following messages to be sent in the following order. None of the messages are posted; the thread falls out of the WinSetFocus() code only after every one of them is processed:

WM_FOCUSCHANGE, false       /* Sent first to the old focus      */
                            /*  window, then sent up until it   */
                            /*  hits the frame.                 */
    WM_ACTIVATE, false      /* Sent to this frame, then down to */
                            /*  the client.                     */
    WM_SETSELECTION, false  /* Sent to old focus window.        */
    WM_SETFOCUS, false      /* Sent to old focus window.        */

WM_FOCUSCHANGE, true        /* Sent first to the new focus      */
                            /*  window, then sent up until it   */
                            /*  hits the frame.                 */
    WM_SETFOCUS, true       /* Sent to new focus window.        */
    WM_SETSELECTION, true   /* Sent to new focus window.        */
    WM_ACTIVATE, true       /* Sent to frame, then down to      */
                            /*  the client.                     */

This entire scenario is complicated by several factors. For example, the WM_QUERYFOCUSCHAIN message is sent repeatedly, and at several different times, in order to determine what the focus chain is. Also, the WM_ACTIVATE message is sent first to the frame window. The default behavior of a frame window is to send this message back down to its client window, if there is one.

Copyright Microsoft Corporation 1991.