Search code examples
.netwinformsfocuslost-focus

Determine Where Activation Is Going When A Form Is Deactivated


Does anyone know of a way to determine which window is going to receive focus when a form is deactivated?


Solution

  • I found the answer. Instead of subscribing to the activated and deactivate events, handle the WM_ACTIVATE message (used for both activation and deactivation) in WndProc. Since it reports the handle of the window being activated, I can compare that handle to the handles of my forms and determine if focus is changing to any of them.

    const int WM_ACTIVATE = 0x0006;
    const int WA_INACTIVE = 0;
    const int WA_ACTIVE = 1;  
    const int WA_CLICKACTIVE = 2;  
    
    protected override void WndProc(ref Message m)  
    {  
        if (m.Msg == WM_ACTIVATE)  
        {  
             // When m.WParam is WA_INACTIVE, the window is being deactivated and
             // m.LParam is the handle of the window that will be activated.
    
             // When m.WParam is WA_ACTIVE or WA_CLICKACTIVE, the window is being 
             // activated and m.LParam is the handle of the window that has been 
             // deactivated.
        }  
    
        base.WndProc(ref m);  
    } 
    

    Edit: This method can be used outside the window it applies to (e.g. outside in a popup window).

    You can use NativeWindow to attach to any window based on its handle and view its message loop. See code example below:

    public class Popup : Form
    {
        const int WM_ACTIVATE = 0x0006;
        const int WA_INACTIVE = 0;
        private ParentWindowIntercept parentWindowIntercept;
    
        public Popup(IntPtr hWndParent)
        {
            this.parentWindowIntercept = new ParentWindowIntercept(hWndParent);
        }
    
        private class ParentWindowIntercept : NativeWindow
        {
            public ParentWindowIntercept(IntPtr hWnd)
            {
                this.AssignHandle(hWnd);
            }
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_ACTIVATE)
                {
                    if ((int)m.WParam == WA_INACTIVE)
                    {
                        IntPtr windowFocusGoingTo = m.LParam;
                        // Compare handles here
                    }
                }
    
                base.WndProc(ref m);
            } 
        }
    }