File: src\Framework\System\Windows\Documents\WinEventHandler.cs
Project: wpf\PresentationFramework.csproj (PresentationFramework)
//---------------------------------------------------------------------------
//
// <copyright file=WinEventHandler.cs company=Microsoft>
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
//
// Description: WinEventHandler implementation.
//
// History:
//  02/04/2005 : yutakas - created.
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using System.Windows.Threading;
using MS.Win32;
 
using MS.Internal;
 
namespace System.Windows.Documents
{
    internal class WinEventHandler : IDisposable
    {
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        #region Constructors
 
        // ctor that takes a range of events
        /// <SecurityNote>
        /// Critical - as this calls the setter for _winEventProc.Value.
        /// Safe - as this doesn't allow an arbitrary value to be set.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal WinEventHandler(int eventMin, int eventMax)
        {
            _eventMin = eventMin;
            _eventMax = eventMax;
 
            _winEventProc.Value = new NativeMethods.WinEventProcDef(WinEventDefaultProc);
            // Keep the garbage collector from moving things around
            _gchThis = GCHandle.Alloc(_winEventProc.Value);
 
            // Workaround for bug 150666.
            _shutdownListener = new WinEventHandlerShutDownListener(this);
        }
 
        ~WinEventHandler()
        {
            Clear();
        }
 
        #endregion Constructors
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        public void Dispose()
        {
            // no need to call this finalizer.
 
            GC.SuppressFinalize(this);
            Clear();
        }
 
        // callback for the class inherited from this.
        internal virtual void WinEventProc(int eventId, IntPtr hwnd)
        {
        }
 
        /// <SecurityNote>
        ///     Critical: This code frees the gchandle and is critical because it calls GCHandle
        ///     TreatAsSafe: Ok to call free on a handle that we have allocated
        /// </SecurityNote>
        [SecurityCritical,SecurityTreatAsSafe]
        internal void Clear()
        {
            // Make sure that the hooks is uninitialzied.
            Stop();
 
            // free GC handle.
            if (_gchThis.IsAllocated)
            {
                _gchThis.Free();
            }
        }
 
        // install WinEvent hook and start getting the callback.
        /// <SecurityNote>
        /// Critical - as this calls SetWinEventHook which has a SUC on it and also calls
        ///            the setter for _hHook.
        /// Safe - as this does not allow an arbitrary method to be set up as a hook and
        ///        also doesn't allow an aribtrary value to be set on _hHook.Value.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal void Start()
        {
            if (_gchThis.IsAllocated)
            {
                _hHook.Value = UnsafeNativeMethods.SetWinEventHook(_eventMin, _eventMax, IntPtr.Zero, _winEventProc.Value,
                                                             0, 0, NativeMethods.WINEVENT_OUTOFCONTEXT);
                if (_hHook.Value == IntPtr.Zero )
                {
                    Stop();
                }
            }
        }
 
        // uninstall WinEvent hook.
        /// <SecurityNote>
        /// Critical - as this calls UnhookWinEvent which has a SUC on it and also
        ///            calls the setter for _hHook.Value.
        /// Safe - as this does not allow an arbitrary hook to be removed and sets
        ///        _hHook.Value to IntPtr.Zero which is safe.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal void Stop()
        {
            if (_hHook.Value != IntPtr.Zero )
            {
                UnsafeNativeMethods.UnhookWinEvent(_hHook.Value);
                _hHook.Value = IntPtr.Zero ;
            }
 
            if (_shutdownListener != null)
            {
                _shutdownListener.StopListening();
                _shutdownListener = null;
            }
        }
 
        #endregion Internal Methods
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        private void WinEventDefaultProc(int winEventHook, int eventId, IntPtr hwnd, int idObject, int idChild, int eventThread, int eventTime)
        {
            WinEventProc(eventId , hwnd);
        }
 
        #endregion Private Methods
 
        #region Private Types
 
        private sealed class WinEventHandlerShutDownListener : ShutDownListener
        {
            /// <SecurityNote>
            ///     Critical: accesses AppDomain.DomainUnload event
            ///     TreatAsSafe: This code does not take any parameter or return state.
            ///                  It simply attaches private callbacks.
            /// </SecurityNote>
            [SecurityCritical,SecurityTreatAsSafe]
            public WinEventHandlerShutDownListener(WinEventHandler target)
                : base(target, ShutDownEvents.DispatcherShutdown)
            {
            }
 
            internal override void OnShutDown(object target, object sender, EventArgs e)
            {
                WinEventHandler winEventHandler = (WinEventHandler)target;
                winEventHandler.Stop();
            }
        }
 
        #endregion Private Types
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        // min WinEvent.
        private int _eventMin;
 
        // max WinEvent.
        private int _eventMax;
 
        // hook handle
        private SecurityCriticalDataForSet<IntPtr> _hHook;
 
        // the callback.
        private SecurityCriticalDataForSet<NativeMethods.WinEventProcDef> _winEventProc;
 
        // GCHandle to keep the garbage collector from moving things around
        private GCHandle _gchThis;
 
        // shutdown listener
        private WinEventHandlerShutDownListener _shutdownListener;
 
        #endregion Private Fields
    }
}