HwndMouseInputProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / InterOp / HwndMouseInputProvider.cs / 1 / HwndMouseInputProvider.cs

                            using System.Windows.Threading; 
using System.Windows.Input;
using System.Windows.Media;
using System.Runtime.InteropServices;
using System.Diagnostics; 
using System.Security;
using System.Security.Permissions; 
using MS.Internal; 
using MS.Internal.PresentationCore;                        // SecurityHelper
using MS.Win32; 
using MS.Utility; // ExceptionStringTable

using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Interop 
{ 
    internal sealed class HwndMouseInputProvider : DispatcherObject, IMouseInputProvider, IDisposable
    { 
        /// 
        ///     Accesses and store critical data. This class is also critical (_site,_source)
        /// 
        [SecurityCritical] 
        internal HwndMouseInputProvider(HwndSource source)
        { 
            (new UIPermission(PermissionState.Unrestricted)).Assert(); 
            try //Blessed Assert for InputManager.Current.RegisterInputProvider
            { 

                 _site = new SecurityCriticalDataClass(InputManager.Current.RegisterInputProvider(this));
            }
            finally 
            {
                 UIPermission.RevertAssert(); 
            } 

            _source = new SecurityCriticalDataClass(source); 

            // MITIGATION_SETCURSOR
            _setCursorState = SetCursorState.SetCursorNotReceived;
            _haveCapture = false; 
            _queryCursorOperation = null;
        } 
 
        /// 
        ///     Critical:This class accesses critical data, _site. 
        ///     TreatAsSafe: This class does not expose the critical data
        /// 
        [SecurityCritical,SecurityTreatAsSafe]
        public void Dispose() 
        {
            if(_site != null) 
            { 
                //Console.WriteLine("Disposing");
 
                // Cleanup the mouse tracking.
                StopTracking(_source.Value.CriticalHandle);

                // If we have capture, release it. 
                try
                { 
                    Debug.Assert(null != _source && null != _source.Value); 

                    if(_source.Value.HasCapture ) 
                    {
                        SafeNativeMethods.ReleaseCapture();
                    }
                } 
                catch(System.ComponentModel.Win32Exception)
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: Dispose: GetCapture failed!"); 
                }
 
                // Possibly deactivate the mouse input stream since our window is going away.
                try
                {
                    IntPtr hwndCapture = SafeNativeMethods.GetCapture(); 
                    PossiblyDeactivate(hwndCapture, false);
                } 
                catch(System.ComponentModel.Win32Exception) 
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: Dispose: GetCapture failed!"); 
                }

                _site.Value.Dispose();
                _site = null; 
            }
            _source = null; 
        } 

        ///  
        ///     Critical: This method acceses critical data hwndsource.
        ///     TreatAsSafe:Information about whether a given input provider services
        ///     a visual is safe to expose. This method does not expose the critical data either.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        bool IInputProvider.ProvidesInputForRootVisual(Visual v) 
        { 
            Debug.Assert(null != _source && null != _source.Value);
 
            return _source.Value.RootVisual == v;
        }

        ///  
        ///     Critical: This method acceses critical data hwndsource.
        ///     TreatAsSafe: The method has no return value, and deactivating the mouse, while 
        ///     perhaps a nuisance, is not a security risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        void IInputProvider.NotifyDeactivate()
        {
            if(_active)
            { 
                StopTracking(_source.Value.CriticalHandle);
 
                _active = false; 
            }
        } 

        // Set the real cursor
        /// 
        ///     Critical: This method acceses critical data hwndsource and calls unmanaged code 
        ///     TreatAsSafe: This is a safe operation to expose.
        ///  
        [SecurityCritical,SecurityTreatAsSafe] 
        bool IMouseInputProvider.SetCursor(Cursor cursor)
        { 
            bool success = false;

            // MITIGATION_SETCURSOR
            // If the _setCursortState flag is set to disabled, disallow the operation 
            // - this is set if we have received a WM_MOUSEMOVE without a prior WM_SETCURSOR, a scenario
            //   that occurs during "Help Mode" where Win32 has set the cursor to an arrow with a question mark 
            //   and does not want the underlying window changing it. 
            if(_setCursorState != SetCursorState.SetCursorDisabled)
            { 
                try
                {
                    SafeNativeMethods.SetCursor( cursor.Handle );
                    success = true; 
                }
                catch(System.ComponentModel.Win32Exception) 
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: SetCursor failed!");
                } 

            }

            return success; 
        }
 
        ///  
        ///     Critical: This method acceses critical data hwndsource also causes elevation via call to GetCursorPos
        ///     TreatAsSafe: This data about who has mouse capture is ok to give out 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        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; 
        } 

        ///  
        ///     Critical: This method acceses critical data hwndsource
        ///     TreatAsSafe: This data about who has mouse capture is ok to give out
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        void IMouseInputProvider.ReleaseMouseCapture()
        { 
            // MITIGATION_SETCURSOR 
            _haveCapture = false;
 
            if(_isDwmProcess)
            {
                return;
            } 

            try 
            { 
                SafeNativeMethods.ReleaseCapture();
            } 
            catch(System.ComponentModel.Win32Exception)
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: ReleaseCapture failed!");
            } 
        }
 
        ///  
        /// GetIntermediatePoints
        ///  
        /// points will be returned relative to this element
        /// relative points prior to the current mouse point (including the current one)
        /// Count of points if succeeded , -1 if error
        ///  
        /// SecurityCritical: This code calls into unsafe native methods
        /// SecurityTreatAsSafe: We are adding the demand 
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        int IMouseInputProvider.GetIntermediatePoints(IInputElement relativeTo, Point[] points) 
        {
            SecurityHelper.DemandUnmanagedCode();
            int cpt = -1;
 
            try
            { 
                if (points != null && relativeTo != null) 
                {
                    DependencyObject containingVisual = InputElement.GetContainingVisual(relativeTo as DependencyObject); 
                    HwndSource inputSource = PresentationSource.FromDependencyObject(containingVisual) as HwndSource;

                    if (inputSource != null)
                    { 
                        int nVirtualWidth  = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CXVIRTUALSCREEN);
                        int nVirtualHeight = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CYVIRTUALSCREEN); 
                        int nVirtualLeft   = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_XVIRTUALSCREEN); 
                        int nVirtualTop    = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_YVIRTUALSCREEN);
                        uint mode           = NativeMethods.GMMP_USE_DISPLAY_POINTS; 

                        NativeMethods.MOUSEMOVEPOINT mp_in  = new NativeMethods.MOUSEMOVEPOINT();
                        NativeMethods.MOUSEMOVEPOINT[] mp_out = new NativeMethods.MOUSEMOVEPOINT[64];
 
                        mp_in.x = _latestMovePoint.x;
                        mp_in.y = _latestMovePoint.y; 
                        mp_in.time = 0;     // don't use a timestamp here, none of the timestamps we have actually work 

                        // get all points in the system buffer 
                        int n = UnsafeNativeMethods.GetMouseMovePointsEx((uint)(Marshal.SizeOf(mp_in)), ref mp_in, mp_out, 64, mode);
                        if (n == -1)
                        {
                            throw new System.ComponentModel.Win32Exception(); 
                        }
 
                        // decide which points to return 
                        cpt = 0;
                        bool ignore = true; 
                        for (int i = 0; i < n && cpt < points.Length; i++)
                        {
                            // ignore points that happened after the latest MouseMove
                            if (ignore) 
                            {
                                if (mp_out[i].time < _latestMovePoint.time || 
                                    (mp_out[i].time == _latestMovePoint.time && 
                                     mp_out[i].x == _latestMovePoint.x &&
                                     mp_out[i].y == _latestMovePoint.y)) 
                                {
                                    ignore = false;
                                }
                                else 
                                {
                                    continue; 
                                } 
                            }
 
                            // stop when we reach the previous MouseMove point,
                            // or a point that happened earlier
                            if (mp_out[i].time < _previousMovePoint.time ||
                                (mp_out[i].time == _previousMovePoint.time && 
                                 mp_out[i].x == _previousMovePoint.x &&
                                 mp_out[i].y == _previousMovePoint.y)) 
                            { 
                                break;
                            } 

                            Point currentPosition = new Point(mp_out[i].x, mp_out[i].y);

                            switch (mode) 
                            {
                                case NativeMethods.GMMP_USE_DISPLAY_POINTS: 
                                    { 
                                        if (currentPosition.X > 32767)
                                            currentPosition.X -= 65536; 

                                        if (currentPosition.Y > 32767)
                                            currentPosition.Y -= 65536;
                                    } 
                                    break;
 
                                case NativeMethods.GMMP_USE_HIGH_RESOLUTION_POINTS: 
                                    {
                                        currentPosition.X = ((currentPosition.X * (nVirtualWidth - 1)) - (nVirtualLeft * 65536)) / nVirtualWidth; 
                                        currentPosition.Y = ((currentPosition.Y * (nVirtualHeight - 1)) - (nVirtualTop * 65536)) / nVirtualHeight;
                                    }
                                    break;
                            } 

                            currentPosition = PointUtil.ScreenToClient(currentPosition, inputSource); 
                            currentPosition = PointUtil.ClientToRoot(currentPosition, inputSource); 

                            // Translate the point from the root to the visual. 
                            GeneralTransform gDown = inputSource.RootVisual.TransformToDescendant(VisualTreeHelper.GetContainingVisual2D(containingVisual));
                            if (gDown != null)
                            {
                                // 
                                gDown.TryTransform(currentPosition, out currentPosition);
                            } 
 
                            points[cpt++] = currentPosition;
                        } 
                    }
                }
            }
            catch(System.ComponentModel.Win32Exception) 
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetIntermediatePoints failed!"); 
 
                cpt = -1;
            } 

            return cpt;
        }
 

        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 
        ///  
        ///     Critical: This code is critical since it handles all mouse messages and could be used to spoof input
        ///  
        [SecurityCritical]
        internal IntPtr FilterMessage(IntPtr hwnd, int 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 == NativeMethods.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(pmq->uMsg == NativeMethods.WM_MOUSEMOVE) 
                    {
                        msg = (int)pmq->uMsg; 
                        wParam = pmq->wParam; 
                        lParam = MakeLPARAM(pmq->ptX, pmq->ptY);
                    } 
                }
            }

            switch(msg) 
            {
                case NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.WM_LBUTTONDBLCLK:
                case NativeMethods.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 NativeMethods.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 NativeMethods.WM_RBUTTONDBLCLK:
                case NativeMethods.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 NativeMethods.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 NativeMethods.WM_MBUTTONDBLCLK: 
                case NativeMethods.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 NativeMethods.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 NativeMethods.WM_XBUTTONDBLCLK:
                case NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.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.Flags.performance, EventTrace.Level.normal))
            {
                // 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();

                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HWNDMESSAGEGUID),
                                                     MS.Utility.EventType.Info, 
                                                     dispatcherHashCode,
                                                     hwnd.ToInt64(), 
                                                     msg, 
                                                     (int)wParam,
                                                     (int)lParam); 
            }

            return result;
        } 

        ///  
        ///     Critical: This code cause an elevation to unmanaged code, it also can be 
        ///         used to cause focus changes. It calls into ReportInput which is critical
        ///         Also, it calls WindowFromPoint which is a SecurityCritical function 
        /// 
        [SecurityCritical]
        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;
            } 
        } 

        ///  
        ///     Critical: accesses _tme field
        /// 
        [SecurityCritical]
        private void StartTracking(IntPtr hwnd) 
        {
            if(!_tracking && !_isDwmProcess) 
            { 
                _tme.hwndTrack = hwnd;
                _tme.dwFlags = NativeMethods.TME_LEAVE; 
                try
                {
                    SafeNativeMethods.TrackMouseEvent(_tme);
                    _tracking = true; 
                }
                catch(System.ComponentModel.Win32Exception) 
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: TrackMouseEvent failed!");
                } 
            }
        }

        ///  
        ///     Critical: accesses _tme field
        ///  
        [SecurityCritical] 
        private void StopTracking(IntPtr hwnd)
        { 
            if(_tracking && !_isDwmProcess)
            {
                _tme.hwndTrack = hwnd;
                _tme.dwFlags = NativeMethods.TME_CANCEL | NativeMethods.TME_LEAVE; 
                try
                { 
                    SafeNativeMethods.TrackMouseEvent(_tme); 
                    _tracking = false;
                } 
                catch(System.ComponentModel.Win32Exception)
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: TrackMouseEvent failed!");
                } 
            }
        } 
 
        private IntPtr MakeLPARAM(int high, int low)
        { 
               return ((IntPtr)((high << 16) | (low & 0xffff)));
        }

        ///  
        ///     Critical: This code accesses code that could expose Hwndsource
        ///     TreatAsSafe: This code uses the parameter locally and does not expose any private 
        ///                  information. 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private bool IsOurWindow(IntPtr hwnd)
        {
            bool isOurWindow = false;
 
            Debug.Assert(null != _source && null != _source.Value);
 
            if(hwnd != IntPtr.Zero) 
            {
                HwndSource hwndSource; 
                hwndSource = HwndSource.CriticalFromHwnd(hwnd);

                if(hwndSource != null)
                { 
                    if(hwndSource.Dispatcher == _source.Value.Dispatcher)
                    { 
                        // The window has the same dispatcher, must be ours. 
                        isOurWindow = true;
                    } 
                    else
                    {
                        // The window has a different dispatcher, must not be ours.
                        isOurWindow = false; 
                    }
                } 
                else 
                {
                    // The window is non-Avalon. 
                    // Such windows are never ours.
                    isOurWindow = false;
                }
            } 
            else
            { 
                // This is not even a window. 
                isOurWindow = false;
            } 

            return isOurWindow;
        }
 
        /// 
        ///     Critical:This code can cause input simulation and hence is critical. 
        ///     The current code path is only hit under RootBrowserWindow scenario for 
        ///     now. But the critical tag exists to prevent additional hookups since this
        ///     code can be used for spoofing. 
        ///     Also, it calls WindowFromPoint which is a SecurityCritical function
        /// 
        [SecurityCritical]
        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.AbsoluteMove) 
                { 
                    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;
        } 


        // GetIntermediatePoints needs to know the time and position of the
        // last two MouseMove events, so that it can extract points from the 
        // system buffer between these two.  This method is called at each
        // MouseMove event to record the required information. 
        ///  
        ///     Critical: This code accesses critical field _source
        ///     TreatAsSafe: This code uses the field locally and does not expose any private 
        ///                  information.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void RecordMouseMove(int x, int y, int timestamp) 
        {
            // (x,y) is in client coordinates, but the system buffer uses screen 
            // coordinates.  Convert the new position into screen coordinates. 
            Point currentPosition = new Point(x, y);
            currentPosition = PointUtil.ClientToScreen(currentPosition, _source.Value); 

            // roll the MouseMove buffer forward
            _previousMovePoint = _latestMovePoint;
 
            _latestMovePoint.x = ((int)currentPosition.X) & 0x0000FFFF;  //Ensure that this number will pass through.
            _latestMovePoint.y = ((int)currentPosition.Y) & 0x0000FFFF;  //Ensure that this number will pass through. 
            _latestMovePoint.time = timestamp; 
        }
 

        /// 
        /// Critical:This is got under an elevation and is hence critical
        /// This class also holds methods that can be used to spoof input 
        /// 
        private SecurityCriticalDataClass _source; 
        ///  
        /// Critical:This is got under an elevation and is hence critical
        /// This class also holds methods that can be used to spoof input 
        /// 
        private  SecurityCriticalDataClass _site;
        private int _msgTime;
        private NativeMethods.MOUSEMOVEPOINT _latestMovePoint;      // screen coordinates 
        private NativeMethods.MOUSEMOVEPOINT _previousMovePoint;    // screen coordinates
        private int _lastX;     // client coordinates 
        private int _lastY; 

        private bool _tracking; // Whether or not we have called TrackMouse() to get a WM_MOUSELEAVE.  This essentaully means IsOver. 
        private bool _active; // Whether or not the mouse is actively sending events to the input manager.

        // MITIGATION_SETCURSOR
        private SetCursorState _setCursorState; // Have we received a WM_SETCURSOR message lately? 
        private bool _haveCapture; // Do we currently have capture?
        private DispatcherOperation _queryCursorOperation; 
 
        private bool _isDwmProcess; // If we are the DWM, we need to always be _active, don't track focus.
 
        /// 
        ///     Do not expose _tme to partial trust, it contains an HWND
        /// 
        [SecurityCritical] 
        private NativeMethods.TRACKMOUSEEVENT _tme = new NativeMethods.TRACKMOUSEEVENT();
 
        // MITIGATION_SETCURSOR 
        //
        // Windows can have a "context help" button in the title bar.  When the user 
        // clicks it, the cursor is changed to a "help" cursor, and when the user
        // clicks somewhere in the window, a WM_HELP message is sent to the child
        // window to tell it to display a help tooltip.
        // 
        // During this time, the application should not be setting the cursor.  Win32
        // accomplishes this by not sending the WM_SETCURSOR message while in this 
        // help mode.  Thus applications do not typically set the cursor.  However, 
        // Win32 does not prevent a programatic call to SetCursor() from changing the
        // cursor. 
        //
        // Avalon programatically changes the cursor on every mouse move.  This is
        // because we simulate mouse moves in response to layout and animation.  The
        // cursor needs to reflect the control it is over, and that control needs to 
        // know the mouse is over it.
        // 
        // But we need to supress setting the cursor while in this "help" mode to 
        // prevent the cursor from being reset to a standard arrow (or whatever the
        // app might want it to be).  There are a number of ways we could accomplish 
        // this:
        //
        // 1) Poke User32 to simulate the mouse for us.
        //    Presumably User32 would supress sending the WM_SETCURSOR properly, and 
        //    we could then only set the cursor in response to a WM_SETCURSOR message.
        //    Unfortunately we can't figure out a way of invoking xxxSetFMouseMoved() 
        //    without encountering unwanted side effects. 
        // 2) Detect the help mode and suppress the cursor only then.
        //    We could listen for WM_SYSCOMMAND(SC_CONTEXTHELP), but this won't be 
        //    sent to us if we are a child window.  Instead we have a little state
        //    machine we drive of the WM_SETCURSOR and WM_MOUSEMOVE messages to
        //    try to detect this mode indirectly.
        private enum SetCursorState 
        {
            SetCursorNotReceived, 
            SetCursorReceived, 
            SetCursorDisabled
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System.Windows.Threading; 
using System.Windows.Input;
using System.Windows.Media;
using System.Runtime.InteropServices;
using System.Diagnostics; 
using System.Security;
using System.Security.Permissions; 
using MS.Internal; 
using MS.Internal.PresentationCore;                        // SecurityHelper
using MS.Win32; 
using MS.Utility; // ExceptionStringTable

using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Interop 
{ 
    internal sealed class HwndMouseInputProvider : DispatcherObject, IMouseInputProvider, IDisposable
    { 
        /// 
        ///     Accesses and store critical data. This class is also critical (_site,_source)
        /// 
        [SecurityCritical] 
        internal HwndMouseInputProvider(HwndSource source)
        { 
            (new UIPermission(PermissionState.Unrestricted)).Assert(); 
            try //Blessed Assert for InputManager.Current.RegisterInputProvider
            { 

                 _site = new SecurityCriticalDataClass(InputManager.Current.RegisterInputProvider(this));
            }
            finally 
            {
                 UIPermission.RevertAssert(); 
            } 

            _source = new SecurityCriticalDataClass(source); 

            // MITIGATION_SETCURSOR
            _setCursorState = SetCursorState.SetCursorNotReceived;
            _haveCapture = false; 
            _queryCursorOperation = null;
        } 
 
        /// 
        ///     Critical:This class accesses critical data, _site. 
        ///     TreatAsSafe: This class does not expose the critical data
        /// 
        [SecurityCritical,SecurityTreatAsSafe]
        public void Dispose() 
        {
            if(_site != null) 
            { 
                //Console.WriteLine("Disposing");
 
                // Cleanup the mouse tracking.
                StopTracking(_source.Value.CriticalHandle);

                // If we have capture, release it. 
                try
                { 
                    Debug.Assert(null != _source && null != _source.Value); 

                    if(_source.Value.HasCapture ) 
                    {
                        SafeNativeMethods.ReleaseCapture();
                    }
                } 
                catch(System.ComponentModel.Win32Exception)
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: Dispose: GetCapture failed!"); 
                }
 
                // Possibly deactivate the mouse input stream since our window is going away.
                try
                {
                    IntPtr hwndCapture = SafeNativeMethods.GetCapture(); 
                    PossiblyDeactivate(hwndCapture, false);
                } 
                catch(System.ComponentModel.Win32Exception) 
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: Dispose: GetCapture failed!"); 
                }

                _site.Value.Dispose();
                _site = null; 
            }
            _source = null; 
        } 

        ///  
        ///     Critical: This method acceses critical data hwndsource.
        ///     TreatAsSafe:Information about whether a given input provider services
        ///     a visual is safe to expose. This method does not expose the critical data either.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        bool IInputProvider.ProvidesInputForRootVisual(Visual v) 
        { 
            Debug.Assert(null != _source && null != _source.Value);
 
            return _source.Value.RootVisual == v;
        }

        ///  
        ///     Critical: This method acceses critical data hwndsource.
        ///     TreatAsSafe: The method has no return value, and deactivating the mouse, while 
        ///     perhaps a nuisance, is not a security risk. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        void IInputProvider.NotifyDeactivate()
        {
            if(_active)
            { 
                StopTracking(_source.Value.CriticalHandle);
 
                _active = false; 
            }
        } 

        // Set the real cursor
        /// 
        ///     Critical: This method acceses critical data hwndsource and calls unmanaged code 
        ///     TreatAsSafe: This is a safe operation to expose.
        ///  
        [SecurityCritical,SecurityTreatAsSafe] 
        bool IMouseInputProvider.SetCursor(Cursor cursor)
        { 
            bool success = false;

            // MITIGATION_SETCURSOR
            // If the _setCursortState flag is set to disabled, disallow the operation 
            // - this is set if we have received a WM_MOUSEMOVE without a prior WM_SETCURSOR, a scenario
            //   that occurs during "Help Mode" where Win32 has set the cursor to an arrow with a question mark 
            //   and does not want the underlying window changing it. 
            if(_setCursorState != SetCursorState.SetCursorDisabled)
            { 
                try
                {
                    SafeNativeMethods.SetCursor( cursor.Handle );
                    success = true; 
                }
                catch(System.ComponentModel.Win32Exception) 
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: SetCursor failed!");
                } 

            }

            return success; 
        }
 
        ///  
        ///     Critical: This method acceses critical data hwndsource also causes elevation via call to GetCursorPos
        ///     TreatAsSafe: This data about who has mouse capture is ok to give out 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        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; 
        } 

        ///  
        ///     Critical: This method acceses critical data hwndsource
        ///     TreatAsSafe: This data about who has mouse capture is ok to give out
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        void IMouseInputProvider.ReleaseMouseCapture()
        { 
            // MITIGATION_SETCURSOR 
            _haveCapture = false;
 
            if(_isDwmProcess)
            {
                return;
            } 

            try 
            { 
                SafeNativeMethods.ReleaseCapture();
            } 
            catch(System.ComponentModel.Win32Exception)
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: ReleaseCapture failed!");
            } 
        }
 
        ///  
        /// GetIntermediatePoints
        ///  
        /// points will be returned relative to this element
        /// relative points prior to the current mouse point (including the current one)
        /// Count of points if succeeded , -1 if error
        ///  
        /// SecurityCritical: This code calls into unsafe native methods
        /// SecurityTreatAsSafe: We are adding the demand 
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        int IMouseInputProvider.GetIntermediatePoints(IInputElement relativeTo, Point[] points) 
        {
            SecurityHelper.DemandUnmanagedCode();
            int cpt = -1;
 
            try
            { 
                if (points != null && relativeTo != null) 
                {
                    DependencyObject containingVisual = InputElement.GetContainingVisual(relativeTo as DependencyObject); 
                    HwndSource inputSource = PresentationSource.FromDependencyObject(containingVisual) as HwndSource;

                    if (inputSource != null)
                    { 
                        int nVirtualWidth  = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CXVIRTUALSCREEN);
                        int nVirtualHeight = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_CYVIRTUALSCREEN); 
                        int nVirtualLeft   = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_XVIRTUALSCREEN); 
                        int nVirtualTop    = UnsafeNativeMethods.GetSystemMetrics(NativeMethods.SM_YVIRTUALSCREEN);
                        uint mode           = NativeMethods.GMMP_USE_DISPLAY_POINTS; 

                        NativeMethods.MOUSEMOVEPOINT mp_in  = new NativeMethods.MOUSEMOVEPOINT();
                        NativeMethods.MOUSEMOVEPOINT[] mp_out = new NativeMethods.MOUSEMOVEPOINT[64];
 
                        mp_in.x = _latestMovePoint.x;
                        mp_in.y = _latestMovePoint.y; 
                        mp_in.time = 0;     // don't use a timestamp here, none of the timestamps we have actually work 

                        // get all points in the system buffer 
                        int n = UnsafeNativeMethods.GetMouseMovePointsEx((uint)(Marshal.SizeOf(mp_in)), ref mp_in, mp_out, 64, mode);
                        if (n == -1)
                        {
                            throw new System.ComponentModel.Win32Exception(); 
                        }
 
                        // decide which points to return 
                        cpt = 0;
                        bool ignore = true; 
                        for (int i = 0; i < n && cpt < points.Length; i++)
                        {
                            // ignore points that happened after the latest MouseMove
                            if (ignore) 
                            {
                                if (mp_out[i].time < _latestMovePoint.time || 
                                    (mp_out[i].time == _latestMovePoint.time && 
                                     mp_out[i].x == _latestMovePoint.x &&
                                     mp_out[i].y == _latestMovePoint.y)) 
                                {
                                    ignore = false;
                                }
                                else 
                                {
                                    continue; 
                                } 
                            }
 
                            // stop when we reach the previous MouseMove point,
                            // or a point that happened earlier
                            if (mp_out[i].time < _previousMovePoint.time ||
                                (mp_out[i].time == _previousMovePoint.time && 
                                 mp_out[i].x == _previousMovePoint.x &&
                                 mp_out[i].y == _previousMovePoint.y)) 
                            { 
                                break;
                            } 

                            Point currentPosition = new Point(mp_out[i].x, mp_out[i].y);

                            switch (mode) 
                            {
                                case NativeMethods.GMMP_USE_DISPLAY_POINTS: 
                                    { 
                                        if (currentPosition.X > 32767)
                                            currentPosition.X -= 65536; 

                                        if (currentPosition.Y > 32767)
                                            currentPosition.Y -= 65536;
                                    } 
                                    break;
 
                                case NativeMethods.GMMP_USE_HIGH_RESOLUTION_POINTS: 
                                    {
                                        currentPosition.X = ((currentPosition.X * (nVirtualWidth - 1)) - (nVirtualLeft * 65536)) / nVirtualWidth; 
                                        currentPosition.Y = ((currentPosition.Y * (nVirtualHeight - 1)) - (nVirtualTop * 65536)) / nVirtualHeight;
                                    }
                                    break;
                            } 

                            currentPosition = PointUtil.ScreenToClient(currentPosition, inputSource); 
                            currentPosition = PointUtil.ClientToRoot(currentPosition, inputSource); 

                            // Translate the point from the root to the visual. 
                            GeneralTransform gDown = inputSource.RootVisual.TransformToDescendant(VisualTreeHelper.GetContainingVisual2D(containingVisual));
                            if (gDown != null)
                            {
                                // 
                                gDown.TryTransform(currentPosition, out currentPosition);
                            } 
 
                            points[cpt++] = currentPosition;
                        } 
                    }
                }
            }
            catch(System.ComponentModel.Win32Exception) 
            {
                System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: GetIntermediatePoints failed!"); 
 
                cpt = -1;
            } 

            return cpt;
        }
 

        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 
        ///  
        ///     Critical: This code is critical since it handles all mouse messages and could be used to spoof input
        ///  
        [SecurityCritical]
        internal IntPtr FilterMessage(IntPtr hwnd, int 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 == NativeMethods.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(pmq->uMsg == NativeMethods.WM_MOUSEMOVE) 
                    {
                        msg = (int)pmq->uMsg; 
                        wParam = pmq->wParam; 
                        lParam = MakeLPARAM(pmq->ptX, pmq->ptY);
                    } 
                }
            }

            switch(msg) 
            {
                case NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.WM_LBUTTONDBLCLK:
                case NativeMethods.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 NativeMethods.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 NativeMethods.WM_RBUTTONDBLCLK:
                case NativeMethods.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 NativeMethods.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 NativeMethods.WM_MBUTTONDBLCLK: 
                case NativeMethods.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 NativeMethods.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 NativeMethods.WM_XBUTTONDBLCLK:
                case NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.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 NativeMethods.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.Flags.performance, EventTrace.Level.normal))
            {
                // 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();

                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HWNDMESSAGEGUID),
                                                     MS.Utility.EventType.Info, 
                                                     dispatcherHashCode,
                                                     hwnd.ToInt64(), 
                                                     msg, 
                                                     (int)wParam,
                                                     (int)lParam); 
            }

            return result;
        } 

        ///  
        ///     Critical: This code cause an elevation to unmanaged code, it also can be 
        ///         used to cause focus changes. It calls into ReportInput which is critical
        ///         Also, it calls WindowFromPoint which is a SecurityCritical function 
        /// 
        [SecurityCritical]
        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;
            } 
        } 

        ///  
        ///     Critical: accesses _tme field
        /// 
        [SecurityCritical]
        private void StartTracking(IntPtr hwnd) 
        {
            if(!_tracking && !_isDwmProcess) 
            { 
                _tme.hwndTrack = hwnd;
                _tme.dwFlags = NativeMethods.TME_LEAVE; 
                try
                {
                    SafeNativeMethods.TrackMouseEvent(_tme);
                    _tracking = true; 
                }
                catch(System.ComponentModel.Win32Exception) 
                { 
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: TrackMouseEvent failed!");
                } 
            }
        }

        ///  
        ///     Critical: accesses _tme field
        ///  
        [SecurityCritical] 
        private void StopTracking(IntPtr hwnd)
        { 
            if(_tracking && !_isDwmProcess)
            {
                _tme.hwndTrack = hwnd;
                _tme.dwFlags = NativeMethods.TME_CANCEL | NativeMethods.TME_LEAVE; 
                try
                { 
                    SafeNativeMethods.TrackMouseEvent(_tme); 
                    _tracking = false;
                } 
                catch(System.ComponentModel.Win32Exception)
                {
                    System.Diagnostics.Debug.WriteLine("HwndMouseInputProvider: TrackMouseEvent failed!");
                } 
            }
        } 
 
        private IntPtr MakeLPARAM(int high, int low)
        { 
               return ((IntPtr)((high << 16) | (low & 0xffff)));
        }

        ///  
        ///     Critical: This code accesses code that could expose Hwndsource
        ///     TreatAsSafe: This code uses the parameter locally and does not expose any private 
        ///                  information. 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private bool IsOurWindow(IntPtr hwnd)
        {
            bool isOurWindow = false;
 
            Debug.Assert(null != _source && null != _source.Value);
 
            if(hwnd != IntPtr.Zero) 
            {
                HwndSource hwndSource; 
                hwndSource = HwndSource.CriticalFromHwnd(hwnd);

                if(hwndSource != null)
                { 
                    if(hwndSource.Dispatcher == _source.Value.Dispatcher)
                    { 
                        // The window has the same dispatcher, must be ours. 
                        isOurWindow = true;
                    } 
                    else
                    {
                        // The window has a different dispatcher, must not be ours.
                        isOurWindow = false; 
                    }
                } 
                else 
                {
                    // The window is non-Avalon. 
                    // Such windows are never ours.
                    isOurWindow = false;
                }
            } 
            else
            { 
                // This is not even a window. 
                isOurWindow = false;
            } 

            return isOurWindow;
        }
 
        /// 
        ///     Critical:This code can cause input simulation and hence is critical. 
        ///     The current code path is only hit under RootBrowserWindow scenario for 
        ///     now. But the critical tag exists to prevent additional hookups since this
        ///     code can be used for spoofing. 
        ///     Also, it calls WindowFromPoint which is a SecurityCritical function
        /// 
        [SecurityCritical]
        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.AbsoluteMove) 
                { 
                    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;
        } 


        // GetIntermediatePoints needs to know the time and position of the
        // last two MouseMove events, so that it can extract points from the 
        // system buffer between these two.  This method is called at each
        // MouseMove event to record the required information. 
        ///  
        ///     Critical: This code accesses critical field _source
        ///     TreatAsSafe: This code uses the field locally and does not expose any private 
        ///                  information.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void RecordMouseMove(int x, int y, int timestamp) 
        {
            // (x,y) is in client coordinates, but the system buffer uses screen 
            // coordinates.  Convert the new position into screen coordinates. 
            Point currentPosition = new Point(x, y);
            currentPosition = PointUtil.ClientToScreen(currentPosition, _source.Value); 

            // roll the MouseMove buffer forward
            _previousMovePoint = _latestMovePoint;
 
            _latestMovePoint.x = ((int)currentPosition.X) & 0x0000FFFF;  //Ensure that this number will pass through.
            _latestMovePoint.y = ((int)currentPosition.Y) & 0x0000FFFF;  //Ensure that this number will pass through. 
            _latestMovePoint.time = timestamp; 
        }
 

        /// 
        /// Critical:This is got under an elevation and is hence critical
        /// This class also holds methods that can be used to spoof input 
        /// 
        private SecurityCriticalDataClass _source; 
        ///  
        /// Critical:This is got under an elevation and is hence critical
        /// This class also holds methods that can be used to spoof input 
        /// 
        private  SecurityCriticalDataClass _site;
        private int _msgTime;
        private NativeMethods.MOUSEMOVEPOINT _latestMovePoint;      // screen coordinates 
        private NativeMethods.MOUSEMOVEPOINT _previousMovePoint;    // screen coordinates
        private int _lastX;     // client coordinates 
        private int _lastY; 

        private bool _tracking; // Whether or not we have called TrackMouse() to get a WM_MOUSELEAVE.  This essentaully means IsOver. 
        private bool _active; // Whether or not the mouse is actively sending events to the input manager.

        // MITIGATION_SETCURSOR
        private SetCursorState _setCursorState; // Have we received a WM_SETCURSOR message lately? 
        private bool _haveCapture; // Do we currently have capture?
        private DispatcherOperation _queryCursorOperation; 
 
        private bool _isDwmProcess; // If we are the DWM, we need to always be _active, don't track focus.
 
        /// 
        ///     Do not expose _tme to partial trust, it contains an HWND
        /// 
        [SecurityCritical] 
        private NativeMethods.TRACKMOUSEEVENT _tme = new NativeMethods.TRACKMOUSEEVENT();
 
        // MITIGATION_SETCURSOR 
        //
        // Windows can have a "context help" button in the title bar.  When the user 
        // clicks it, the cursor is changed to a "help" cursor, and when the user
        // clicks somewhere in the window, a WM_HELP message is sent to the child
        // window to tell it to display a help tooltip.
        // 
        // During this time, the application should not be setting the cursor.  Win32
        // accomplishes this by not sending the WM_SETCURSOR message while in this 
        // help mode.  Thus applications do not typically set the cursor.  However, 
        // Win32 does not prevent a programatic call to SetCursor() from changing the
        // cursor. 
        //
        // Avalon programatically changes the cursor on every mouse move.  This is
        // because we simulate mouse moves in response to layout and animation.  The
        // cursor needs to reflect the control it is over, and that control needs to 
        // know the mouse is over it.
        // 
        // But we need to supress setting the cursor while in this "help" mode to 
        // prevent the cursor from being reset to a standard arrow (or whatever the
        // app might want it to be).  There are a number of ways we could accomplish 
        // this:
        //
        // 1) Poke User32 to simulate the mouse for us.
        //    Presumably User32 would supress sending the WM_SETCURSOR properly, and 
        //    we could then only set the cursor in response to a WM_SETCURSOR message.
        //    Unfortunately we can't figure out a way of invoking xxxSetFMouseMoved() 
        //    without encountering unwanted side effects. 
        // 2) Detect the help mode and suppress the cursor only then.
        //    We could listen for WM_SYSCOMMAND(SC_CONTEXTHELP), but this won't be 
        //    sent to us if we are a child window.  Instead we have a little state
        //    machine we drive of the WM_SETCURSOR and WM_MOUSEMOVE messages to
        //    try to detect this mode indirectly.
        private enum SetCursorState 
        {
            SetCursorNotReceived, 
            SetCursorReceived, 
            SetCursorDisabled
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK