public Data(SnapPoint snapPoint, IntPtr hWndChild, IntPtr hWndOwner, IntPtr hWndSnap)
 {
     this.snapPoint = snapPoint;
     SnapHandle     = hWndSnap;
     nwChild        = new ChildNW(hWndChild, this);
     nwOwner        = new OwnerNW(hWndOwner, this);
 }
            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);

                if (m.Msg == WM_SHOWWINDOW)
                {
                    RECT rChild = new RECT();
                    RECT rOwner = new RECT();
                    GetWindowRect(data.SnapHandle, ref rOwner);
                    SnapPoint sp = data.snapPoint;
                    if (sp.NeedsChildRect)
                    {
                        GetWindowRect(Handle, ref rChild);
                    }

                    // must do this, otherwise when the window is invisible (e.g. owner is minimized) then its location resets
                    Point pt = sp.GetLocation(rChild, rOwner);
                    SetWindowPos(Handle, IntPtr.Zero, pt.X, pt.Y, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
                }
            }
            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);

                // several different approaches were tried, such as WM_MOVING, WM_MOVED, WM_WINDOWPOSCHANGING
                // WM_MOVING and WM_MOVED do not account for resizing the window. WM_WINDOWPOSCHANGING fires
                // false events (e.g. clicking on the title bar near (but not on) the minimize window button).
                if (m.Msg == WM_WINDOWPOSCHANGED)
                {
                    WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
                    // -32000 means the window is minimized.
                    if (pos.x > -32000 && pos.y > -32000)
                    {
                        RECT rChild = new RECT();
                        RECT rOwner = new RECT();
                        if (data.SnapHandle == Handle)
                        {
                            rOwner.Top    = pos.y;
                            rOwner.Left   = pos.x;
                            rOwner.Bottom = pos.y + pos.cy;
                            rOwner.Right  = pos.x + pos.cx;
                        }
                        else
                        {
                            GetWindowRect(data.SnapHandle, ref rOwner);
                        }

                        SnapPoint sp = data.snapPoint;
                        if (sp.NeedsChildRect)
                        {
                            GetWindowRect(data.nwChild.Handle, ref rChild);
                        }

                        Point pt = sp.GetLocation(rChild, rOwner);
                        SetWindowPos(data.nwChild.Handle, IntPtr.Zero, pt.X, pt.Y, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
                    }
                }
            }
        public static void SetOwner(IntPtr hWndChild, IntPtr hWndParent, IntPtr hWndTopLevel, SnapPoint snapPoint)
        {
            Data d = (Data)htData[hWndChild];

            if (d != null)
            {
                d.nwOwner.ReleaseHandle();
                if (hWndTopLevel != IntPtr.Zero)
                {
                    d.nwOwner = new OwnerNW(hWndTopLevel, d);
                }
                else
                {
                    d.nwChild.ReleaseHandle();
                    htData.Remove(hWndChild);
                }
            }
            else
            {
                if (hWndTopLevel == IntPtr.Zero)
                {
                    return;
                }

                d = new Data(snapPoint, hWndChild, hWndTopLevel, hWndParent);
                htData[hWndChild] = d;
            }
        }
 ///<summary>Snaps the child window to the top level owner window, relative to the hWndSnap window. As
 ///the top level owner window is moved, resized, minimized or maximized, the child window moves too.</summary>
 ///<param name="child">The control that is automtically moved, e.g. a ToolStripDropDown window.</param>
 ///<param name="hWndTopLevel">A handle to a top-level window, e.g. a Form control's Handle.</param>
 ///<param name="hWndParent">A handle to a control that child window is relatively positioned, e.g. a TextBox or ComoBox.</param>
 ///<param name="snapPoint">Parameters that specify the X and Y location.</param>
 public static void SnapWindow(this Control child, IntPtr hWndParent, IntPtr hWndTopLevel, SnapPoint snapPoint)
 {
     if (child.IsHandleCreated)
     {
         SetOwner(child.Handle, hWndParent, hWndTopLevel, snapPoint);
     }
     else
     {
         child.HandleCreated += delegate
         {
             SetOwner(child.Handle, hWndParent, hWndTopLevel, snapPoint);
         };
     }
 }