Exemple #1
0
        public void GetACPFromPoint(int viewCookie, ref UnsafeNativeMethods.POINT tsfPoint, UnsafeNativeMethods.GetPositionFromPointFlags flags, out int positionCP)
        {
            SecurityHelper.DemandUnmanagedCode();

            PresentationSource source;
            IWin32Window win32Window;
            CompositionTarget compositionTarget;
            ITextView view;
            Point milPoint;
            ITextPointer position;
            NativeMethods.POINT point;

            point = new NativeMethods.POINT(tsfPoint.x, tsfPoint.y);
            GetVisualInfo(out source, out win32Window, out view);
            compositionTarget = source.CompositionTarget;

            // Convert to client coordinates.
            SafeNativeMethods.ScreenToClient(new HandleRef(null,win32Window.Handle), point);

            // Convert to mil measure units.
            milPoint = new Point(point.x, point.y);
            milPoint = compositionTarget.TransformFromDevice.Transform(milPoint);

            // Convert to local coordinates.
            GeneralTransform transform = compositionTarget.RootVisual.TransformToDescendant(RenderScope);
            if (transform != null)
            {
                // 
                transform.TryTransform(milPoint, out milPoint);
            }

            // Validate layout information on TextView
            if (!view.Validate(milPoint))
            {
                throw new COMException(SR.Get(SRID.TextStore_TS_E_NOLAYOUT), UnsafeNativeMethods.TS_E_NOLAYOUT);
            }

            // Do the hittest.
            position = view.GetTextPositionFromPoint(milPoint, (flags & UnsafeNativeMethods.GetPositionFromPointFlags.GXFPF_NEAREST) != 0 /* snapToText */);
            if (position == null)
            {
                // GXFPF_ROUND_NEAREST was clear and we didn't hit a char.
                throw new COMException(SR.Get(SRID.TextStore_TS_E_INVALIDPOINT), UnsafeNativeMethods.TS_E_INVALIDPOINT);
            }

            positionCP = position.CharOffset;
            if ((flags & UnsafeNativeMethods.GetPositionFromPointFlags.GXFPF_ROUND_NEAREST) == 0)
            {
                // Check if the point is on the backward position of the TextPosition.
                Rect rectCur;
                Rect rectPrev;
                Point milPointTopLeft;
                Point milPointBottomRight;

                ITextPointer positionCur = position.CreatePointer(LogicalDirection.Backward);
                ITextPointer positionPrev = position.CreatePointer(LogicalDirection.Forward);
                positionPrev.MoveToNextInsertionPosition(LogicalDirection.Backward);

                rectCur = view.GetRectangleFromTextPosition(positionCur);
                rectPrev = view.GetRectangleFromTextPosition(positionPrev);

                // Take the "extended" union of the previous char's bounding box.
                milPointTopLeft = new Point(Math.Min(rectPrev.Left, rectCur.Left), Math.Min(rectPrev.Top, rectCur.Top));
                milPointBottomRight = new Point(Math.Max(rectPrev.Left, rectCur.Left), Math.Max(rectPrev.Bottom, rectCur.Bottom));

                // The rect of the previous char.
                Rect rectTest = new Rect(milPointTopLeft, milPointBottomRight);
                if (rectTest.Contains(milPoint))
                    positionCP--;
            }
        }
Exemple #2
0
        private IntPtr CreateWindow(NativeMethods.BitmapHandle hBitmap, int width, int height, bool topMost)
        {
            if (_defWndProc == null)
            {
                _defWndProc = new MS.Win32.NativeMethods.WndProc(UnsafeNativeMethods.DefWindowProc);
            }

            MS.Win32.NativeMethods.WNDCLASSEX_D wndClass = new MS.Win32.NativeMethods.WNDCLASSEX_D();
            wndClass.cbSize = Marshal.SizeOf(typeof(MS.Win32.NativeMethods.WNDCLASSEX_D));
            wndClass.style = 3; /* CS_HREDRAW | CS_VREDRAW */
            wndClass.lpfnWndProc = null;
            wndClass.hInstance = _hInstance;
            wndClass.hCursor = IntPtr.Zero;
            wndClass.lpszClassName = CLASSNAME;
            wndClass.lpszMenuName = string.Empty;
            wndClass.lpfnWndProc = _defWndProc;

            // We chose to ignore re-registration errors in RegisterClassEx on the off chance that the user
            // wants to open multiple splash screens.
            _wndClass = MS.Win32.UnsafeNativeMethods.IntRegisterClassEx(wndClass);
            if (_wndClass == 0)
            {
                if (Marshal.GetLastWin32Error() != 0x582) /* class already registered */
                    throw new Win32Exception();
            }

            int screenWidth = MS.Win32.UnsafeNativeMethods.GetSystemMetrics(SM.CXSCREEN);
            int screenHeight = MS.Win32.UnsafeNativeMethods.GetSystemMetrics(SM.CYSCREEN);
            int x = (screenWidth - width) / 2;
            int y = (screenHeight - height) / 2;

            HandleRef nullHandle = new HandleRef(null, IntPtr.Zero);
            int windowCreateFlags =
                (int) NativeMethods.WS_EX_WINDOWEDGE |
                      NativeMethods.WS_EX_TOOLWINDOW |
                      NativeMethods.WS_EX_LAYERED |
                      (topMost ? NativeMethods.WS_EX_TOPMOST : 0);

            // CreateWindowEx will either succeed or throw
            IntPtr hWnd =  MS.Win32.UnsafeNativeMethods.CreateWindowEx(
                windowCreateFlags,
                CLASSNAME, SR.Get(SRID.SplashScreenIsLoading),
                MS.Win32.NativeMethods.WS_POPUP | MS.Win32.NativeMethods.WS_VISIBLE,
                x, y, width, height,
                nullHandle, nullHandle, new HandleRef(null, _hInstance), IntPtr.Zero);

            // Display the image on the window
            IntPtr hScreenDC = UnsafeNativeMethods.GetDC(new HandleRef());
            IntPtr memDC = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hScreenDC));
            IntPtr hOldBitmap = UnsafeNativeMethods.SelectObject(new HandleRef(null, memDC), hBitmap.MakeHandleRef(null).Handle);

            NativeMethods.POINT newSize = new NativeMethods.POINT(width, height);
            NativeMethods.POINT newLocation = new NativeMethods.POINT(x, y);
            NativeMethods.POINT sourceLocation = new NativeMethods.POINT(0, 0);
            _blendFunc = new NativeMethods.BLENDFUNCTION();
            _blendFunc.BlendOp = NativeMethods.AC_SRC_OVER;
            _blendFunc.BlendFlags = 0;
            _blendFunc.SourceConstantAlpha = 255;
            _blendFunc.AlphaFormat = 1; /*AC_SRC_ALPHA*/

            bool result = UnsafeNativeMethods.UpdateLayeredWindow(hWnd, hScreenDC, newLocation, newSize,
                memDC, sourceLocation, 0, ref _blendFunc, NativeMethods.ULW_ALPHA);

            UnsafeNativeMethods.SelectObject(new HandleRef(null, memDC), hOldBitmap);
            UnsafeNativeMethods.ReleaseDC(new HandleRef(), new HandleRef(null, memDC));
            UnsafeNativeMethods.ReleaseDC(new HandleRef(), new HandleRef(null, hScreenDC));

            if (result == false)
            {
                UnsafeNativeMethods.HRESULT.Check(Marshal.GetHRForLastWin32Error());
            }

            return hWnd;
        }
Exemple #3
0
                private NativeMethods.POINT GetWindowScreenLocation(FlowDirection flowDirection)
                {
                    Debug.Assert(IsSourceWindowNull != true, "IsSourceWindowNull cannot be true here");
                    NativeMethods.POINT pt = new NativeMethods.POINT(0, 0);
                    if (flowDirection == FlowDirection.RightToLeft)
                    {
                        NativeMethods.RECT rc = new NativeMethods.RECT(0, 0, 0, 0);

                        // with RTL window, GetClientRect returns reversed coordinates
                        SafeNativeMethods.GetClientRect(new HandleRef(this, CriticalHandle), ref rc);

                        // note that we use rc.right here for the RTL case and client to screen that point
                        pt = new NativeMethods.POINT(rc.right, rc.top);
                    }
                    UnsafeNativeMethods.ClientToScreen(new HandleRef(this, _sourceWindow.CriticalHandle), pt);

                    return pt;
                }
Exemple #4
0
        private static UnsafeNativeMethods.RECT TransformRootRectToScreenCoordinates(Point milPointTopLeft, Point milPointBottomRight, IWin32Window win32Window, PresentationSource source)
        {
            UnsafeNativeMethods.RECT rect;
            NativeMethods.POINT clientPoint;
            CompositionTarget compositionTarget;

            rect = new UnsafeNativeMethods.RECT();

            // Transform to device units.
            compositionTarget = source.CompositionTarget;
            milPointTopLeft = compositionTarget.TransformToDevice.Transform(milPointTopLeft);
            milPointBottomRight = compositionTarget.TransformToDevice.Transform(milPointBottomRight);

            IntPtr hwnd = IntPtr.Zero;
            new UIPermission(UIPermissionWindow.AllWindows).Assert(); // BlessedAssert
            try
            {
                hwnd = win32Window.Handle;
            }
            finally
            {
                CodeAccessPermission.RevertAssert();
            }

            // Transform to screen coords.
            clientPoint = new NativeMethods.POINT();
            UnsafeNativeMethods.ClientToScreen(new HandleRef(null, hwnd), /* ref by interop */ clientPoint);

            rect.left = (int)(clientPoint.x + milPointTopLeft.X);
            rect.right = (int)(clientPoint.x + milPointBottomRight.X);
            rect.top = (int)(clientPoint.y + milPointTopLeft.Y);
            rect.bottom = (int)(clientPoint.y + milPointBottomRight.Y);
            return rect;
        }
        private void PossiblyDeactivate(IntPtr hwndCapture, bool stillActiveIfOverSelf)
        {
            // we may have been disposed by a re-entrant call (bug 1536643).
            // If so, there's nothing more to do.
            if (null == _source || null == _source.Value )
            {
                return;
            }

            if(_isDwmProcess)
            {
                return;
            }

            //Console.WriteLine("PossiblyDeactivate(" + hwndCapture + ")");

            // We are now longer active ourselves, but it is possible that the
            // window the mouse is going to intereact with is in the same
            // Dispatcher as ourselves.  If so, we don't want to deactivate the
            // mouse input stream because the other window hasn't activated it
            // yet, and it may result in the input stream "flickering" between
            // active/inactive/active.  This is ugly, so we try to supress the
            // uneccesary transitions.
            //
            IntPtr hwndToCheck = hwndCapture;
            if(hwndToCheck == IntPtr.Zero)
            {
                NativeMethods.POINT ptCursor = new NativeMethods.POINT();
                int messagePos = 0;
                try
                {
                    messagePos = SafeNativeMethods.GetMessagePos();
                }
                catch(System.ComponentModel.Win32Exception)
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessagePos failed!");
                }

                ptCursor.x = NativeMethods.SignedLOWORD(messagePos);
                ptCursor.y = NativeMethods.SignedHIWORD(messagePos);
                //Console.WriteLine("  GetMessagePos: ({0},{1})", ptCursor.x, ptCursor.y);

                try
                {
                    hwndToCheck = UnsafeNativeMethods.WindowFromPoint(ptCursor.x, ptCursor.y);
                }
                catch(System.ComponentModel.Win32Exception)
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: WindowFromPoint failed!");
                }

                if (!stillActiveIfOverSelf && hwndToCheck == _source.Value.CriticalHandle)
                {
                    hwndToCheck = IntPtr.Zero;
                }

                if(hwndToCheck != IntPtr.Zero)
                {
                    // We need to check if the point is over the client or
                    // non-client area.  We only care about being over the
                    // non-client area.
                    try
                    {
                        NativeMethods.RECT rcClient = new NativeMethods.RECT();
                        SafeNativeMethods.GetClientRect(new HandleRef(this,hwndToCheck), ref rcClient);
                        SafeNativeMethods.ScreenToClient(new HandleRef(this,hwndToCheck), ptCursor);

                        if(ptCursor.x < rcClient.left || ptCursor.x >= rcClient.right ||
                           ptCursor.y < rcClient.top || ptCursor.y >= rcClient.bottom)
                        {
                            // We are not over the non-client area.  We can bail out.
                            //Console.WriteLine("  No capture, mouse outside of client area.");
                            //Console.WriteLine("  Client Area: ({0},{1})-({2},{3})", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
                            //Console.WriteLine("  Mouse: ({0},{1})", ptCursor.x, ptCursor.y);
                            hwndToCheck = IntPtr.Zero;
                        }
                    }
                    catch(System.ComponentModel.Win32Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetClientRect or ScreenToClient failed!");
                    }
                }
            }

            // If the window the mouse is over is ours, we'll just let it activate
            // without deactivating the mouse input stream for this window.  This prevents
            // the mouse input stream from flickering.
            bool deactivate = !IsOurWindow(hwndToCheck);

            //Console.WriteLine("  Deactivate=" + deactivate);

            // Only deactivate the mouse input stream if needed.
            if(deactivate)
            {
                ReportInput(_source.Value.CriticalHandle,
                            InputMode.Foreground,
                            _msgTime,
                            RawMouseActions.Deactivate,
                            0,
                            0,
                            0);
            }
            else
            {
                // We are not deactivating the mouse input stream because the
                // window that is going to provide mouse input next is one of
                // our Avalon windows.  This optimization keeps the mouse input
                // stream from flickering by transitioning to null.
                //
                // But this window itself should not be active anymore.
                _active = false;
            }
        }
Exemple #6
0
        IntPtr GetCurrentMonitorFromMousePosition()
        {
            SecurityHelper.DemandUnmanagedCode();
            // center on the screen on which the mouse is on
            NativeMethods.POINT pt = new NativeMethods.POINT();

            UnsafeNativeMethods.TryGetCursorPos(pt);

            NativeMethods.POINTSTRUCT ptStruct = new NativeMethods.POINTSTRUCT(pt.x, pt.y);
            return SafeNativeMethods.MonitorFromPoint(ptStruct, NativeMethods.MONITOR_DEFAULTTONEAREST);
        }
        bool IMouseInputProvider.CaptureMouse()
        {
            if(_isDwmProcess)
            {
                return true;
            }

            bool success = true;

            Debug.Assert(null != _source && null != _source.Value);

            try
            {
                SafeNativeMethods.SetCapture(new HandleRef(this,_source.Value.CriticalHandle));
                IntPtr capture = SafeNativeMethods.GetCapture();
                if (capture != _source.Value.CriticalHandle)
                {
                    success = false;
                }
            }
            catch(System.ComponentModel.Win32Exception)
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: SetCapture or GetCapture failed!");

                success = false;
            }

            // MITIGATION_
            if(success)
            {
                _haveCapture = true;
            }

            // WORKAROUND for bug 969748
            if(success && !_active)
            {
                NativeMethods.POINT ptCursor = new NativeMethods.POINT();

                success = UnsafeNativeMethods.TryGetCursorPos(ptCursor);

                if(success)
                {
                    try
                    {
                        SafeNativeMethods.ScreenToClient(new HandleRef(this, _source.Value.CriticalHandle), ptCursor);
                    }
                    catch(System.ComponentModel.Win32Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: ScreenToClient failed!");

                        success = false;
                    }

                    if(success)
                    {
                        ReportInput(_source.Value.CriticalHandle,
                                    InputMode.Foreground,
                                    _msgTime,
                                    RawMouseActions.AbsoluteMove,
                                    ptCursor.x,
                                    ptCursor.y,
                                    0);
                    }
                }
            }

            return success;
        }
        internal IntPtr FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            IntPtr result = IntPtr.Zero ;

            // It is possible to be re-entered during disposal.  Just return.
            if(null == _source || null == _source.Value)
            {
                return result;
            }
            /*
            NativeMethods.POINT ptCursor = new NativeMethods.POINT();
            int messagePos = 0;
            try
            {
                messagePos = SafeNativeMethods.GetMessagePos();
            }
            catch(System.ComponentModel.Win32Exception)
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessagePos failed!");
            }

            ptCursor.x = NativeMethods.SignedLOWORD(messagePos);
            ptCursor.y = NativeMethods.SignedHIWORD(messagePos);
            Console.WriteLine("HwndMouseInputProvider.FilterMessage: hwnd: {0} msg: {1} wParam: {2} lParam: {3} MessagePos: ({4},{5})", hwnd, msg, wParam, lParam, ptCursor.x, ptCursor.y);
            */
            _msgTime = 0;
            try
            {
                _msgTime = SafeNativeMethods.GetMessageTime();
            }
            catch(System.ComponentModel.Win32Exception)
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessageTime failed!");
            }

            // 
            if(msg == WindowMessage.WM_MOUSEQUERY)
            {
                if(!_isDwmProcess)
                {
                    _isDwmProcess = true;
                }

                unsafe
                {
                    // Currently only sending WM_MOUSEMOVE through until we rip out the prototype bits.
                    UnsafeNativeMethods.MOUSEQUERY* pmq = (UnsafeNativeMethods.MOUSEQUERY*)lParam;
                    if((WindowMessage)pmq->uMsg == WindowMessage.WM_MOUSEMOVE)
                    {
                        msg = (WindowMessage)pmq->uMsg;
                        wParam = pmq->wParam;
                        lParam = MakeLPARAM(pmq->ptX, pmq->ptY);
                    }
                }
            }

            switch(msg)
            {
                // Compatibility Note:
                //
                // WM_POINTERUP, WM_POINTERDOWN
                //
                // These messages were introduced in Win8 to unify the various
                // mechanisms for processing events from pointing devices,
                // including stylus, touch, mouse, etc.  WPF does not
                // currently support these messages; we still rely on the
                // classic WM_MOUSE messages.  For classic applications, this
                // is supported by default in Windows.  However, for immersive
                // applications, the default is to report mouse input through
                // these new WM_POINTER messages.  Blend - the only immersive
                // WPF application - must explicitly request the mouse input
                // be delivered through the traditional WM_MOUSE messages by
                // calling EnableMouseInPointer(false).  If WPF ever supports
                // the WM_POINTER messages, we need to be careful not to break
                // Blend.
                
                case WindowMessage.WM_NCDESTROY:
                {
                    //Console.WriteLine("WM_NCDESTROY");

                    // This is the normal clean-up path.  HwndSource destroys the
                    // HWND first, which should trigger this code, before it
                    // explicitly disposes us.  This allows us to call
                    // PossiblyDeactivate since our window is no longer on the
                    // screen.
                    Dispose();
                }
                break;

                case WindowMessage.WM_MOUSEMOVE:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    //Console.WriteLine("WM_MOUSEMOVE: " + x + "," + y);

                    // Abort the pending operation waiting to update the cursor, because we
                    // are going to update it as part of this mouse move processing.
                    if (_queryCursorOperation != null)
                    {
                        _queryCursorOperation.Abort();
                        _queryCursorOperation = null;
                    }

                    // MITIGATION_SETCURSOR
                    if (_haveCapture)
                    {
                        // When we have capture we don't receive WM_SETCURSOR
                        // prior to a mouse move.  So that we don't erroneously think
                        // we're in "Help Mode" we'll pretend we've received a set
                        // cursor message.
                        _setCursorState = SetCursorState.SetCursorReceived;
                    }
                    else
                    {
                        if (_setCursorState == SetCursorState.SetCursorNotReceived)
                        {
                            _setCursorState = SetCursorState.SetCursorDisabled;
                        }
                        else if(_setCursorState == SetCursorState.SetCursorReceived)
                        {
                            _setCursorState = SetCursorState.SetCursorNotReceived;
                        }
                    }

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.AbsoluteMove,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_MOUSEWHEEL:
                {
                    int wheel = NativeMethods.SignedHIWORD(wParam);
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    // The WM_MOUSEWHEEL gives the coordinates relative to the desktop.
                    NativeMethods.POINT pt = new NativeMethods.POINT(x,y);
                    try
                    {
                        SafeNativeMethods.ScreenToClient(new HandleRef(this,hwnd), pt);

                        x = pt.x;
                        y = pt.y;

                        //Console.WriteLine("WM_MOUSEWHEEL: " + x + "," + y + "," + wheel);

                        // 

                        handled = ReportInput(hwnd,
                                              InputMode.Foreground,
                                              _msgTime,
                                              RawMouseActions.VerticalWheelRotate,
                                              x,
                                              y,
                                              wheel);
                    }
                    catch(System.ComponentModel.Win32Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: ScreenToClient failed!");
                    }
                }
                break;

                case WindowMessage.WM_LBUTTONDBLCLK:
                case WindowMessage.WM_LBUTTONDOWN:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    //Console.WriteLine("WM_LBUTTONDOWN: " + x + "," + y);

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.Button1Press,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_LBUTTONUP:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    //Console.WriteLine("WM_LBUTTONUP: " + x + "," + y);

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.Button1Release,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_RBUTTONDBLCLK:
                case WindowMessage.WM_RBUTTONDOWN:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.Button2Press,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_RBUTTONUP:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.Button2Release,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_MBUTTONDBLCLK:
                case WindowMessage.WM_MBUTTONDOWN:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.Button3Press,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_MBUTTONUP:
                {
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          RawMouseActions.Button3Release,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_XBUTTONDBLCLK:
                case WindowMessage.WM_XBUTTONDOWN:
                {
                    int button = NativeMethods.SignedHIWORD(wParam);
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    RawMouseActions actions = 0;
                    if(button == 1)
                    {
                        actions = RawMouseActions.Button4Press;
                    }
                    else if(button == 2)
                    {
                        actions = RawMouseActions.Button5Press;
                    }

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          actions,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_XBUTTONUP:
                {
                    int button = NativeMethods.SignedHIWORD(wParam);
                    int x = NativeMethods.SignedLOWORD(lParam);
                    int y = NativeMethods.SignedHIWORD(lParam);

                    RawMouseActions actions = 0;
                    if(button == 1)
                    {
                        actions = RawMouseActions.Button4Release;
                    }
                    else if(button == 2)
                    {
                        actions = RawMouseActions.Button5Release;
                    }

                    // 

                    handled = ReportInput(hwnd,
                                          InputMode.Foreground,
                                          _msgTime,
                                          actions,
                                          x,
                                          y,
                                          0);
                }
                break;

                case WindowMessage.WM_MOUSELEAVE:
                {
                    //Console.WriteLine("WM_MOUSELEAVE");

                    // When the mouse moves off the window, we receive a
                    // WM_MOUSELEAVE.   We'll start tracking again when the
                    // mouse moves back over us.
                    StopTracking(hwnd);

                    // It is possible that we have capture but we still receive
                    // a mouse leave event.  This can happen in the case of
                    // "soft capture".  In such cases, we defer the actual
                    // deactivation until the capture is lost.
                    //
                    // See the note on WM_CAPTURECHANGED for more details.
                    try
                    {
                        IntPtr hwndCapture = SafeNativeMethods.GetCapture();
                        IntPtr hwndCurrent = _source.Value.CriticalHandle;
                        if (hwndCapture != hwndCurrent)
                        {
                            PossiblyDeactivate(hwndCapture, false);
                        }
                    }
                    catch(System.ComponentModel.Win32Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetCapture failed!");
                    }

            }
                break;

                case WindowMessage.WM_CAPTURECHANGED:
                {
                    //Console.WriteLine("WM_CAPTURECHANGED");

                    // Win32 has two concepts for capture:
                    //
                    // Hard Capture
                    // When a mouse button is pressed, Win32 finds the window
                    // underneath the mouse and assigns it as the MouseOwner.
                    // All mouse input is directed to this window until the
                    // mouse is button released.  The window does not even
                    // have to request capture.  Certain window types are
                    // excluded from this processing.
                    //
                    // Soft Capture
                    // This is accessed via the SetCapture API.  It assigns
                    // the window that should receive mouse input for the
                    // queue.  Win32 decides which queue the mouse input
                    // should go to without considering this type of capture.
                    // Once the input is in the queue, it is sent to the
                    // window with capture.  This means that the mouse
                    // messages will generally be sent to the specified window
                    // in the application, but other applications will work
                    // too.
                    //
                    // If another application calls SetCapture, the current
                    // application will receive a WM_CAPTURECHANGED.
                    //
                    // If the window took capture while Win32 was enforcing
                    // Hard Capture, and releases capture when the mouse
                    // button is released, then everything works as you
                    // probably expect.  But if the application retains
                    // capture after the mouse button is released, it is
                    // possible to receive a WM_MOUSELEAVE even though the
                    // window still has capture.

                    // Losing capture *after* a WM_MOUSELEAVE means we
                    // probably want to deactivate the mouse input stream.
                    // If someone else is taking capture, we may need
                    // to deactivate the mouse input stream too.

                    if(lParam != _source.Value.CriticalHandle) // Ignore odd messages that claim we are losing capture to ourselves.
                    {
                        // MITIGATION_SETCURSOR
                        _haveCapture = false;

                        if(_setCursorState == SetCursorState.SetCursorReceived)
                        {
                            _setCursorState = SetCursorState.SetCursorNotReceived;
                        }

                        if(!IsOurWindow(lParam) && _active)
                        {
                            ReportInput(hwnd,
                                        InputMode.Foreground,
                                        _msgTime,
                                        RawMouseActions.CancelCapture,
                                        0,
                                        0,
                                        0);
                        }

                        if(lParam != IntPtr.Zero || // someone else took capture
                           !_tracking)              // OR no one has capture and the mouse is not over us
                        {
                            PossiblyDeactivate(lParam, true);
                        }
                    }
                }
                break;

                case WindowMessage.WM_CANCELMODE:
                {
                    // MITIGATION: NESTED_MESSAGE_PUMPS_INTERFERE_WITH_INPUT
                    //
                    // When a nested message pump runs, it intercepts all messages
                    // before they are dispatched, and thus before they can be sent
                    // to the window with capture.
                    //
                    // This means that an element can take capture on MouseDown,
                    // expecting to receive either MouseUp or LostCapture.  But, in
                    // fact, neither event may be raised if a nested message pump
                    // runs.
                    //
                    // An example of this is displaying a dialog box in response to
                    // MouseDown.
                    //
                    // There isn't much we can do about the general case, but
                    // well-behaved message pumps (such as a dialog box) are
                    // supposed to send the WM_CANCELMODE message.  In response
                    // to this we release capture if we currently have it.
                    try
                    {
                        if(_source.Value.HasCapture )
                        {
                            SafeNativeMethods.ReleaseCapture();
                        }
                    }
                    catch(System.ComponentModel.Win32Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetCapture failed!");
                    }
                }
                break;

                case WindowMessage.WM_SETCURSOR:
                {
                    if (_queryCursorOperation == null)
                    {
                        // It is possible that a WM_SETCURSOR is not followed by a WM_MOUSEMOVE, in which
                        // case we need a backup mechanism to query the cursor and update it. So we post to
                        // the queue to do this work. If a WM_MOUSEMOVE comes in earlier, then the operation
                        // is aborted, else it comes through and we update the cursor.
                        _queryCursorOperation = Dispatcher.BeginInvoke(DispatcherPriority.Input,
                            (DispatcherOperationCallback)delegate(object sender)
                            {
                                // Since this is an asynchronous operation and an arbitrary amount of time has elapsed
                                // since we received the WM_SETCURSOR, we need to be careful that the mouse hasn't
                                // been deactivated in the meanwhile. This is also another reason that we do not ReportInput,
                                // because the implicit assumption in doing that is to activate the MouseDevice. All we want
                                // to do is passively try to update the cursor.
                                if (_active)
                                {
                                    Mouse.UpdateCursor();
                                }

                                _queryCursorOperation = null;
                                return null;
                            },
                            null);
                    }

                    // MITIGATION_SETCURSOR
                    _setCursorState = SetCursorState.SetCursorReceived;

                    // Note: We get this message BEFORE we get WM_MOUSEMOVE.  This means that Avalon
                    //       still thinks the mouse is over the "old" element.  This is awkward, and we think
                    //       people will find it confusing to get a QueryCursor event before a MouseMove event.
                    //       Further, this means we would have to do a special hit-test, and route the
                    //       QueryCursor event differently than the other mouse events.
                    //
                    //       Another difference is that Win32 passes us a hit-test code, which was calculated
                    //       by an earlier WM_NCHITTEST message.  The problem with this is that it is a fixed
                    //       enum.  We don't have a similar concept in Avalon.
                    //
                    //       So instead, the MouseDevice will raise the QueryCursor event after every MouseMove
                    //       event.  We think this is a better ordering.  And the application can return whatever
                    //       cursor they want (not limited to a fixed enum of hit-test codes).
                    //
                    //       Of course, this is different than Win32.  One example of where this can cause a
                    //       problem is that sometimes Win32 will NOT send a WM_SETCURSOR message and just send
                    //       a WM_MOUSEMOVE.  This is for cases like when the mouse is captured, or when the
                    //       the "help mode" is active (clicking the little question mark in the title bar).
                    //       To accomodate this, we use the _setCursorState to prevent the user from changing
                    //       the cursor when we haven't received a WM_SETCURSOR message - which means that the
                    //       cursor is NOT supposed to change as it moves over new windows/elements/etc.  Note
                    //       that Avalon will raise the QueryCursor event, but the result is ignored.
                    //
                    // But:  We MUST mark this Win32 message as "handled" or windows will change the cursor to
                    //       the default cursor, which will cause annoying flicker if the app is trying to set
                    //       a custom one.  Of course, only do this for the client area.
                    //
                    int hittestCode = NativeMethods.SignedLOWORD((int) lParam);
                    if(hittestCode == NativeMethods.HTCLIENT)
                    {
                        handled = true;
                    }
                }
                break;
            }

            if (handled && EventTrace.IsEnabled(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
            {
                // Anything can (and does) happen in ReportInput.  We can be (and have been)
                // re-entered and Dispose()ed.  Then returning from ReportInput
                // needs to check for that.
                int dispatcherHashCode = 0;

                if( _source != null && !_source.Value.IsDisposed && _source.Value.CompositionTarget != null)
                    dispatcherHashCode = _source.Value.CompositionTarget.Dispatcher.GetHashCode();

                // The ETW manifest for this event declares the lParam and
                // wParam values to be integers.  This is not always true for
                // 64-bit systems, which sometimes pass pointers and handles
                // through this parameters.  However, we can't change the ETW
                // manifest in an in-place upgrade, so we are just going to
                // cast to an int.  Note that IntPtr defines the explicit int
                // cast operator to used a checked block, which will throw an
                // overflow exception if the IntPtr contains too big of a value.
                // So we do the cast ourselves and ignore the overflow.
                int wParamInt = (int) (long) wParam;;
                int lParamInt = (int) (long) lParam;
                
                EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientInputMessage, EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info, dispatcherHashCode, hwnd.ToInt64(), msg, wParamInt, lParamInt);

            }

            return result;
        }
        private void GetWindowRectsInScreenCoordinates()
        {
            NativeMethods.RECT rcClient = new NativeMethods.RECT();

            //
            // Get the window and client rectangles
            //

            SafeNativeMethods.GetWindowRect(_hWnd.MakeHandleRef(this), ref _hwndWindowRectInScreenCoords);
            SafeNativeMethods.GetClientRect(_hWnd.MakeHandleRef(this), ref rcClient);


            NativeMethods.POINT ptClientTopLeft = new NativeMethods.POINT(rcClient.left, rcClient.top);
            UnsafeNativeMethods.ClientToScreen(_hWnd.MakeHandleRef(this), ptClientTopLeft);

            NativeMethods.POINT ptClientBottomRight = new NativeMethods.POINT(rcClient.right, rcClient.bottom);
            UnsafeNativeMethods.ClientToScreen(_hWnd.MakeHandleRef(this), ptClientBottomRight);

            if(ptClientBottomRight.x >= ptClientTopLeft.x)
            {
                _hwndClientRectInScreenCoords.left = ptClientTopLeft.x;
                _hwndClientRectInScreenCoords.right = ptClientBottomRight.x;
            }
            else
            {
                // RTL windows will cause the right edge to be on the left...
                _hwndClientRectInScreenCoords.left = ptClientBottomRight.x;
                _hwndClientRectInScreenCoords.right = ptClientTopLeft.x;
            }

            if(ptClientBottomRight.y >= ptClientTopLeft.y)
            {
                _hwndClientRectInScreenCoords.top = ptClientTopLeft.y;
                _hwndClientRectInScreenCoords.bottom = ptClientBottomRight.y;
            }
            else
            {
                // RTL windows will cause the right edge to be on the left...
                // This doesn't affect top/bottom, but the code should be symmetrical.
                _hwndClientRectInScreenCoords.top = ptClientBottomRight.y;
                _hwndClientRectInScreenCoords.bottom = ptClientTopLeft.y;
            }

            // 
        }
        private bool ReportInput(
            IntPtr hwnd,
            InputMode mode,
            int timestamp,
            RawMouseActions actions,
            int x,
            int y,
            int wheel)
        {
            // if there's no HwndSource, we shouldn't get here.  But just in case...
            Debug.Assert(null != _source && null != _source.Value);
            if (_source == null || _source.Value == null)
            {
                return false;
            }

            PresentationSource source = _source.Value;
            CompositionTarget ct = source.CompositionTarget;

            // Input reports should only be generated if the window is still valid.
            if(_site == null || source.IsDisposed || ct == null )
            {
                if(_active)
                {
                    // We are still active, but the window is dead.  Force a deactivate.
                    actions = RawMouseActions.Deactivate;
                }
                else
                {
                    return false;
                }
            }

            if((actions & RawMouseActions.Deactivate) == RawMouseActions.Deactivate)
            {
                // Stop tracking the mouse since we are deactivating.
                StopTracking(hwnd);

                _active = false;
            }
            else if((actions & RawMouseActions.CancelCapture) == RawMouseActions.CancelCapture)
            {
                // We have lost capture, but don't do anything else.
            }
            else if(!_active && (actions & RawMouseActions.VerticalWheelRotate) == RawMouseActions.VerticalWheelRotate)
            {
                // report mouse wheel events as if they came from the window that
                // is under the mouse (even though they are reported to the window
                // with keyboard focus)
                MouseDevice mouse = _site.Value.CriticalInputManager.PrimaryMouseDevice;
                if (mouse != null && mouse.CriticalActiveSource != null)
                {
                    source = mouse.CriticalActiveSource;
                }
            }
            else
            {
                // If we are not active, we need to activate first.
                if(!_active)
                {
                    // But first, check for "spurious" mouse events...
                    //
                    // Sometimes we get a mouse move for window "A" AFTER another
                    // window ("B") has become active.  This would cause "A" to think
                    // that it is active, and to tell Avalon. Now both "A" and "B" think
                    // they are active, and Avalon thinks "A" is, but REALLY, "B" is.
                    //
                    // Confused yet?
                    //
                    // To avoid this, if this window ("A") gets a mouse move,
                    // we verify that either "A" has capture, or the mouse is over "A"

                    IntPtr hwndToCheck = SafeNativeMethods.GetCapture();
                    if(hwnd != hwndToCheck)
                    {
                        // If we get this far, "A" does NOT have capture
                        // - now ensure mouse is over "A"
                        NativeMethods.POINT ptCursor = new NativeMethods.POINT();
                        try
                        {
                            UnsafeNativeMethods.GetCursorPos(ptCursor);
                        }
                        catch(System.ComponentModel.Win32Exception)
                        {
                            // Sometimes Win32 will fail this call, such as if you are
                            // not running in the interactive desktop.  For example,
                            // a secure screen saver may be running.
                            System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetCursorPos failed!");
                        }

                        try
                        {
                            hwndToCheck = UnsafeNativeMethods.WindowFromPoint(ptCursor.x, ptCursor.y);
                        }
                        catch(System.ComponentModel.Win32Exception)
                        {
                            System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: WindowFromPoint failed!");
                        }

                        if(hwnd != hwndToCheck)
                        {
                            // If we get this far:
                            // - the mouse is NOT over "A"
                            // - "A" does NOT have capture
                            // We consider this a "spurious" mouse move and ignore it. (Win32 bug?)
                            System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: Spurious mouse event received!");
                            return false;
                        }
                    }


                    // We need to collect the current state of the mouse.
                    // Include the activation action.
                    actions |= RawMouseActions.Activate;

                    // Remember that we are active.
                    _active = true;
                    _lastX = x;
                    _lastY = y;

                    //Console.WriteLine("Activating the mouse.");
                }

                // Make sure we are tracking the mouse so we know when it
                // leaves the window.
                StartTracking(hwnd);

                // Even if a move isn't explicitly reported, we still may need to
                // report one if the coordinates are different.  This is to cover
                // some ugly edge cases with context menus and such.
                if((actions & RawMouseActions.AbsoluteMove) == 0)
                {
                    if(x != _lastX || y != _lastY)
                    {
                        actions |= RawMouseActions.AbsoluteMove;
                    }
                }
                else
                {
                    _lastX = x;
                    _lastY = y;
                }

                // record mouse motion so that GetIntermediatePoints has the
                // information it needs
                if ((actions & RawMouseActions.AbsoluteMove) != 0)
                {
                    RecordMouseMove(x, y, _msgTime);
                }

                // MITIGATION: WIN32_AND_AVALON_RTL
                //
                // When a window is marked with the WS_EX_LAYOUTRTL style, Win32
                // mirrors the coordinates received for mouse movement as well as
                // mirroring the output of drawing to a GDI DC.
                //
                // Avalon also sets up mirroring transforms so that we properly
                // mirror the output since we render to DirectX, not a GDI DC.
                //
                // Unfortunately, this means that our input is already mirrored
                // by Win32, and Avalon mirrors it again.  To work around this
                // problem, we un-mirror the input from Win32 before passing
                // it into Avalon.
                //
                if((actions & (RawMouseActions.AbsoluteMove | RawMouseActions.Activate)) != 0)
                {
                    try
                    {
                        //This has a SUC on it and accesses CriticalHandle
                        int windowStyle = SafeNativeMethods.GetWindowStyle(new HandleRef(this, _source.Value.CriticalHandle), true);

                        if((windowStyle & NativeMethods.WS_EX_LAYOUTRTL) == NativeMethods.WS_EX_LAYOUTRTL)
                        {
                            NativeMethods.RECT rcClient = new NativeMethods.RECT();
                            SafeNativeMethods.GetClientRect(new HandleRef(this,_source.Value.Handle), ref rcClient);
                            x = rcClient.right - x;
                        }
                    }
                    catch(System.ComponentModel.Win32Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetWindowStyle or GetClientRect failed!");
                    }
                }
            }


            // Get the extra information sent along with the message.
            //There exists a SUC for this native method call
            IntPtr extraInformation = IntPtr.Zero;
            try
            {
                extraInformation = UnsafeNativeMethods.GetMessageExtraInfo();
            }
            catch(System.ComponentModel.Win32Exception)
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetMessageExtraInfo failed!");
            }


            RawMouseInputReport report = new RawMouseInputReport(mode,
                                                                 timestamp,
                                                                 source,
                                                                 actions,
                                                                 x,
                                                                 y,
                                                                 wheel,
                                                                 extraInformation);


            bool handled = _site.Value.ReportInput(report);

            return handled;
        }
        internal IntPtr FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            IntPtr result = IntPtr.Zero ;

            // It is possible to be re-entered during disposal.  Just return.
            if(null == _source || null == _source.Value)
            {
                return result;
            }

            switch(msg)
            {
                case WindowMessage.WM_ENABLE:
                    _stylusLogic.Value.OnWindowEnableChanged(hwnd, (int)NativeMethods.IntPtrToInt32(wParam) == 0);
                    break;

                case WindowMessage.WM_TABLET_QUERYSYSTEMGESTURESTATUS:
                    handled = true;

                    NativeMethods.POINT pt1 = new NativeMethods.POINT(
                                            NativeMethods.SignedLOWORD(lParam),
                                            NativeMethods.SignedHIWORD(lParam));
                    SafeNativeMethods.ScreenToClient(new HandleRef(this, hwnd), pt1);
                    Point ptClient1 = new Point(pt1.x, pt1.y);

                    IInputElement inputElement = StylusDevice.LocalHitTest(_source.Value, ptClient1);
                    if (inputElement != null)
                    {
                        // walk up the parent chain
                        DependencyObject elementCur = (DependencyObject)inputElement;
                        bool isPressAndHoldEnabled = Stylus.GetIsPressAndHoldEnabled(elementCur);
                        bool isFlicksEnabled = Stylus.GetIsFlicksEnabled(elementCur);
                        bool isTapFeedbackEnabled = Stylus.GetIsTapFeedbackEnabled(elementCur);
                        bool isTouchFeedbackEnabled = Stylus.GetIsTouchFeedbackEnabled(elementCur);

                        uint flags = 0;

                        if (!isPressAndHoldEnabled)
                        {
                            flags |= TABLET_PRESSANDHOLD_DISABLED;
                        }

                        if (!isTapFeedbackEnabled)
                        {
                            flags |= TABLET_TAPFEEDBACK_DISABLED;
                        }

                        if (isTouchFeedbackEnabled)
                        {
                            flags |= TABLET_TOUCHUI_FORCEON;
                        }
                        else
                        {
                            flags |= TABLET_TOUCHUI_FORCEOFF;
                        }

                        if (!isFlicksEnabled)
                        {
                            flags |= TABLET_FLICKS_DISABLED;
                        }

                        result = new IntPtr(flags);
                    }
                    break;

                case WindowMessage.WM_TABLET_FLICK:
                    handled = true;

                    int flickData = NativeMethods.IntPtrToInt32(wParam);

                    // We always handle any scroll actions if we are enabled.  We do this when we see the SystemGesture Flick come through.
                    // Note: Scrolling happens on window flicked on even if it is not the active window.
                    if(_stylusLogic != null && _stylusLogic.Value.Enabled && (StylusLogic.GetFlickAction(flickData) == 1))
                    {
                        result = new IntPtr(0x0001); // tell UIHub the flick has already been handled.
                    }
                    break;
            }

            if (handled && EventTrace.IsEnabled(EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientInputMessage, EventTrace.Keyword.KeywordInput | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info,
                                                    (_source.Value.CompositionTarget != null ? _source.Value.CompositionTarget.Dispatcher.GetHashCode() : 0),
                                                     hwnd.ToInt64(),
                                                     msg,
                                                     (int)wParam,
                                                     (int)lParam);
            }

            return result;
        }
        //------------------------------------------------------
        //
        //  Interface ITransformProvider
        //
        //------------------------------------------------------

        #region Interface ITransformProvider

        void ITransformProvider.Move( double x, double y )
        {
            if ( ! ((ITransformProvider)this).CanMove )
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));

            int extendedStyle = GetWindowExStyle();
            if ( IsBitSet(extendedStyle, SafeNativeMethods.WS_EX_MDICHILD) )
            {
                // we always deal in screen pixels.  But if its an MDI window it interprets these as
                // client pixels so convert them to get the expected results.
                NativeMethods.POINT point = new NativeMethods.POINT((int)x, (int)y);
                NativeMethods.HWND hwndParent = SafeNativeMethods.GetAncestor(NativeMethods.HWND.Cast(_hwnd), SafeNativeMethods.GA_PARENT);
                if (!MapWindowPoints(NativeMethods.HWND.NULL, hwndParent, ref point, 1))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }
                x = point.x;
                y = point.y;

                // Make sure the MDI child stays on the parents client area.
                NativeMethods.RECT currentRect = new NativeMethods.RECT();
                if (!Misc.GetWindowRect(_hwnd, out currentRect))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }
                int currentHeight = currentRect.bottom - currentRect.top;
                int currentWidth = currentRect.right - currentRect.left;

                int dx = SafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CXHSCROLL);
                int dy = SafeNativeMethods.GetSystemMetrics(SafeNativeMethods.SM_CYHSCROLL);

                // If to far to the left move right edge to be visible.
                // Move the left edge the absalute differance of the right to the origin plus a little more to be visible.
                if (x + currentWidth < 0)
                {
                    x += ((x + currentWidth) * -1 + dx);
                }
                // If to far off the top move bottom edge down to be visible.
                // Move the top edge the absalute differance of the bottom to the origin plus a little more to be visible.
                if (y + currentHeight < 0)
                {
                    y += ((y + currentHeight) * -1 + dy);
                }

                NativeMethods.RECT parentRect = new NativeMethods.RECT();
                if (!Misc.GetClientRect(hwndParent, out parentRect))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }
                // If to far to the right move left edge to be visible.
                // Move the left edge back the diffance of it and the parent's client area right side plus a little more to be visible.
                if (x > parentRect.right)
                {
                    x -= (x - parentRect.right + dx);
                }
                // If to far off the bottome move top edge down to be visible.
                // Move the top edge up the diffance of it and the parent's client area bottom side plus a little more to be visible.
                if (y > parentRect.bottom)
                {
                    y -= (y - parentRect.bottom + dy);
                }
            }

            // position the window keeping the zorder the same and not resizing.
            // We do this first so that the window is moved in terms of screen coordinates.
            // The WindowPlacement APIs take in to account the workarea which ends up
            // putting the window in the wrong place
            if (!Misc.SetWindowPos(_hwnd, NativeMethods.HWND.NULL, (int)x, (int)y, 0, 0, UnsafeNativeMethods.SWP_NOSIZE | UnsafeNativeMethods.SWP_NOZORDER | UnsafeNativeMethods.SWP_NOACTIVATE))
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            UnsafeNativeMethods.WINDOWPLACEMENT wp = new UnsafeNativeMethods.WINDOWPLACEMENT();
            wp.length = Marshal.SizeOf(typeof(UnsafeNativeMethods.WINDOWPLACEMENT));

            // get the WINDOWPLACEMENT information.  This includes the coordinates in
            // terms of the workarea.
            if (!Misc.GetWindowPlacement(_hwnd, ref wp))
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            int style = GetWindowStyle();
            if (style == 0)
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }
            if ( IsBitSet(style, SafeNativeMethods.WS_MINIMIZE) )
            {
                // If the window is minimized the parameters have to be setup differently
                wp.ptMinPosition.y = (int) y;
                wp.ptMinPosition.x = (int) x;
                wp.flags = UnsafeNativeMethods.WPF_SETMINPOSITION;

                // Use SetWindowPlacement to move the window because it handles the case where the
                // window is move completly off the screen even in the multi-mon case.  If this happens
                // it will place the window on the primary monitor at a location closest to the taget.
                if (!Misc.SetWindowPlacement(_hwnd, ref wp))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }
            }
            else
            {
                NativeMethods.RECT currentRect = new NativeMethods.RECT();

                if (!Misc.GetWindowRect(_hwnd, out currentRect))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }

                // Use SetWindowPlacement to move the window because it handles the case where the
                // window is move completly off the screen even in the multi-mon case.  If this happens
                // it will place the window on the primary monitor at a location closest to the taget.
                if (!Misc.SetWindowPlacement(_hwnd, ref wp))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }

                // check to make sure SetWindowPlacement has not changed the size of our window
                // There may be a bug in SetWindowPlacement.
                int currentHeight = currentRect.bottom - currentRect.top;
                int currentWidth = currentRect.right - currentRect.left;

                if (!Misc.GetWindowPlacement(_hwnd, ref wp))
                {
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                }

                int newHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
                int newWidth = wp.rcNormalPosition.right -wp.rcNormalPosition.left;

                if ( currentHeight != newHeight || currentWidth != newWidth )
                {
                    wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + currentHeight;
                    wp.rcNormalPosition.right = wp.rcNormalPosition.left + currentWidth;

                    if (!Misc.SetWindowPlacement(_hwnd, ref wp))
                    {
                        throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
                    }
                }
            }
        }
        // Get the child window at the specified point.
        // Returns IntPtr.NULL on error; returns original window if point is not
        // on any child window.
        // When the returned window is a child, the out param isClientArea indicates
        // whether the returned point is on the client area of the returned HWND.
        private static NativeMethods.HWND ChildWindowFromPoint( NativeMethods.HWND hwnd, double x, double y, out bool isClientArea )
        {
            NativeMethods.HWND hBestFitTransparent = NativeMethods.HWND.NULL;
            NativeMethods.RECT rcBest = new NativeMethods.RECT();
            isClientArea = true;

            IntPtr hrgn = Misc.CreateRectRgn(0, 0, 0, 0); // NOTE: Must be deleted before returning
            if (hrgn == IntPtr.Zero)
            {
                return NativeMethods.HWND.NULL;
            }

            // Infinite looping is 'possible' (though unlikely) when
            // using GetWindow(...NEXT), so we counter-limit this loop...
            int SanityLoopCount = 1024;
            for (NativeMethods.HWND hChild = Misc.GetWindow(hwnd, SafeNativeMethods.GW_CHILD);
                hChild != NativeMethods.HWND.NULL && --SanityLoopCount > 0 ;
                hChild = Misc.GetWindow(hChild, SafeNativeMethods.GW_HWNDNEXT))
            {
                // Skip invisible...
                if( ! IsWindowReallyVisible( hChild ) )
                    continue;

                // Check for rect...
                NativeMethods.RECT rc = new NativeMethods.RECT();
                if (!Misc.GetWindowRect(hChild, out rc))
                {
                    continue;
                }

                // If on Vista, convert the incoming physical screen coords to hwndChild-relative
                // logical coords before using them in [logical] rect comparisons...
                double xLogical = x;
                double yLogical = y;
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    NativeMethods.HWND hwndTopLevel = SafeNativeMethods.GetAncestor(hChild, SafeNativeMethods.GA_ROOT);
                    NativeMethods.POINT pt = new NativeMethods.POINT((int)x, (int)y);
                    try
                    {
                        SafeNativeMethods.PhysicalToLogicalPoint(hwndTopLevel, ref pt);
                        xLogical = pt.x;
                        yLogical = pt.y;
                    }
                    catch (EntryPointNotFoundException)
                    {
                        // Ignore.
                    }
                }

                if(!PtInRect(rc, xLogical, yLogical))
                {
                    continue;
                }

                // Skip disabled child windows with other controls beneath it.
                // (only a few places actually use this,
                // eg. the Date&Time properties window, which has a disabled edit window
                // over the edits/static for the time components - see WinClient#856699)
                int style = GetWindowStyle(hChild);
                if ((style & SafeNativeMethods.WS_CHILD) != 0
                 && (style & SafeNativeMethods.WS_DISABLED) != 0)
                {
                    int x1 = (rc.left + rc.right) / 2;
                    int y1 = (rc.top + rc.bottom) / 2;
                    IntPtr hwndCompare = UnsafeNativeMethods.WindowFromPhysicalPoint(x1, y1);
                    // The WindowFromPoint function does not retrieve a handle to a hidden or disabled window,
                    // even if the point is within the window.  So we should either get the parents hwnd or
                    // the controls hwnd underneath the disabled control, if one exsists.
                    // 


                    if (hwndCompare != (IntPtr)hwnd)
                    {
                        // This means that there is another child under `the disabled child, so we want to exclude
                        // `the disabled child high in the z-order.
                        continue;
                    }
                }

                // Check for transparent layered windows (eg as used by menu and tooltip shadows)
                // (Note that WS_EX_TRANSPARENT has a specific meaning when used with WS_EX_LAYERED
                // that is different then when it is used alone, so we must check both flags
                // together.)
                int exStyle = GetWindowExStyle(hChild);
                if( ( exStyle & SafeNativeMethods.WS_EX_LAYERED ) != 0
                  && ( exStyle & SafeNativeMethods.WS_EX_TRANSPARENT ) != 0 )
                {
                    continue;
                }

                // If window is using a region (eg. Media Player), check whether
                // point is in it...
                if (SafeNativeMethods.GetWindowRgn(hChild.h, hrgn) == SafeNativeMethods.COMPLEXREGION)
                {
                    // hrgn is relative to window (not client or screen), so offset point appropriately...
                    if (!SafeNativeMethods.PtInRegion(hrgn, (int)xLogical - rc.left, (int)yLogical - rc.top))
                    {
                        continue;
                    }
                }

                // Try for transparency and/or non-client areas:
                IntPtr lr = Misc.SendMessageTimeout( hChild, UnsafeNativeMethods.WM_NCHITTEST, IntPtr.Zero, MAKELPARAM( (int)x, (int)y ) );
                if( lr == UnsafeNativeMethods.HTTRANSPARENT )
                {
                    // For reasons best known to the writers of USER, statics - used
                    // as labels - claim to be transparent. So that we do hit-test
                    // to these, we remember the hwnd here, so if nothing better
                    // comes along, we'll use this.

                    // If we come accross two or more of these, we remember the
                    // one that fits inside the other - if any. That way,
                    // we hit-test to siblings 'within' siblings - eg. statics in
                    // a groupbox.

                    if( hBestFitTransparent == NativeMethods.HWND.NULL )
                    {
                        hBestFitTransparent = hChild;
                        if (!Misc.GetWindowRect(hChild, out rcBest))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // Is this child within the last remembered transparent?
                        // If so, remember it instead.
                        NativeMethods.RECT rcChild = new NativeMethods.RECT();
                        if (!Misc.GetWindowRect(hChild, out rcChild))
                        {
                            continue;
                        }
                        if( Rect1InRect2( rcChild, rcBest ) )
                        {
                            hBestFitTransparent = hChild;
                            rcBest = rcChild;
                        }
                    }

                    continue;
                }

                // Got the window!

                // Using the hit-test result and compairing against HTCLIENT is not good enough.  The Shell_TrayWnd control,
                // i.e. the task bar, will never returns a value of HTCLIENT, so check to see if the point is in the client area.
                NativeMethods.RECT rcClient = new NativeMethods.RECT();
                if (!Misc.GetClientRect(hChild, out rcClient) ||
                    !MapWindowPoints(hChild, NativeMethods.HWND.NULL, ref rcClient, 2) ||
                    !PtInRect(rcClient, xLogical, yLogical))
                {
                    isClientArea = false;
                }

                Misc.DeleteObject(hrgn); // finished with region
                return hChild;
            }

            Misc.DeleteObject(hrgn); // finished with region

            if( SanityLoopCount == 0 )
            {
                Debug.Assert(false, "too many children or inf loop?");
                return NativeMethods.HWND.NULL;
            }

            // Did we find a transparent (eg. a static) on our travels? If so, since
            // we couldn't find anything better, may as well use it.
            if( hBestFitTransparent != NativeMethods.HWND.NULL )
            {
                return hBestFitTransparent;
            }

            // Otherwise return the original window (not NULL!) if no child found...
            return hwnd;
        }
Exemple #14
0
            internal NativeMethods.POINT GetMouseCursorPos(Visual targetVisual)
            {
                if (Mouse.DirectlyOver != null)
                {
                    // get target window info
                    HwndSource hwndSource = null;
                    if (targetVisual != null)
                    {
                        hwndSource = PopupSecurityHelper.GetPresentationSource(targetVisual) as HwndSource;
                    }

                    IInputElement relativeTarget = targetVisual as IInputElement;

                    if (relativeTarget != null)
                    {
                        Point pt = Mouse.GetPosition(relativeTarget);

                        if ((hwndSource != null) && !hwndSource.IsDisposed)
                        {
                            Visual rootVisual = hwndSource.RootVisual;
                            CompositionTarget ct = hwndSource.CompositionTarget;

                            if ((rootVisual != null) && (ct != null))
                            {
                                // Transform the point from the targetVisual to client device units
                                GeneralTransform transformTo = targetVisual.TransformToAncestor(rootVisual);
                                Matrix transform = PointUtil.GetVisualTransform(rootVisual) * ct.TransformToDevice;
                                transformTo.TryTransform(pt, out pt);
                                pt = transform.Transform(pt);

                                // Convert from device client units to screen units
                                return ClientToScreen(hwndSource, pt);
                            }
                        }
                    }
                }

                // This is a fallback if we couldn't convert Mouse.GetPosition
                NativeMethods.POINT mousePoint = new NativeMethods.POINT(0, 0);

                UnsafeNativeMethods.TryGetCursorPos(mousePoint);

                return mousePoint;
            }
 public static extern int IntScreenToClient(HandleRef hWnd, [In, Out] NativeMethods.POINT pt);