// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using MS.Internal;
using MS.Internal.Interop;
using MS.Utility;
using System.Windows;
using System.Windows.Threading;
using System.Security;                       // CAS
using System.Threading;                      // Thread

// The SecurityHelper class differs between assemblies and could not actually be
//  shared, so it is duplicated across namespaces to prevent name collision.
#if WINDOWS_BASE
    using MS.Internal.WindowsBase;
#elif PRESENTATION_CORE
    using MS.Internal.PresentationCore;
#elif PRESENTATIONFRAMEWORK
    using MS.Internal.PresentationFramework;
#elif DRT
    using MS.Internal.Drt;
#else
#error Attempt to use a class (duplicated across multiple namespaces) from an unknown assembly.
#endif

namespace MS.Win32
{
    /// <summary>
    ///     The HwndSubclass class provides a managed way to subclass an existing
    ///     HWND.  This class inserts itself into the WNDPROC chain for the
    ///     window, and will call a specified delegate to process the window
    ///     messages that arrive.  The delegate has a slightly different
    ///     signature than a WNDPROC to be more specific about whether the
    ///     message was handled or not.  If the message was not handled by the
    ///     delegate, this class passes the message on down the WNDPROC chain.
    ///
    ///     To use this class properly, simply:
    ///     1) Create an instance of the HwndSubclass class and pass the delegate
    ///        to the constructor.
    ///     2) Call Attach(HWND) to subclass an existing window.
    ///     3) Call Detach(false) to unsubclass the window when you are done.
    ///
    ///     You can also just call RequestDetach() to send a message to the
    ///     window that will cause the HwndSubclass to detach itself.  This is
    ///     important if you are on a different thread, as the HwndSubclass class
    ///     is not thread safe and will be operated on by the thread that owns
    ///     the window.
    /// </summary>
    /// <remarks> Not available to partial trust callers</remarks>
    [FriendAccessAllowed] // Built into Base, also used by Framework
    internal class HwndSubclass : IDisposable
    {
        /// <SecurityNote>
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///</SecurityNote>
        [SecurityCritical]
        static HwndSubclass()
        {
            DetachMessage = UnsafeNativeMethods.RegisterWindowMessage("HwndSubclass.DetachMessage");

            // Go find the address of DefWindowProc.
            IntPtr hModuleUser32 = UnsafeNativeMethods.GetModuleHandle(ExternDll.User32);
            IntPtr address = UnsafeNativeMethods.GetProcAddress(new HandleRef(null,hModuleUser32), "DefWindowProcW");

            DefWndProc = address;
        }

        /// <summary>
        ///     This HwndSubclass constructor binds the HwndSubclass object to the
        ///     specified delegate.  This delegate will be called to process
        ///     the messages that are sent or posted to the window.
        /// </summary>
        /// <param name="hook">
        ///     The delegate that will be called to process the messages that
        ///     are sent or posted to the window.
        /// </param>
        /// <returns>
        ///     Nothing.
        /// </returns>
        /// <SecurityNote>
        ///  Critical: This code creates an object that is not allowed in partial trust
        /// </SecurityNote>
        [SecurityCritical]
        internal HwndSubclass(HwndWrapperHook hook)
        {
            if(hook == null)
            {
                throw new ArgumentNullException("hook");
            }

            _bond = Bond.Unattached;
            _hook = new WeakReference(hook);

            // Allocate a GC handle so that we won't be collected, even if all
            // references to us get released.  This is because a component outside
            // of the managed code (ie. the window we are subclassing) still holds
            // a reference to us - just not a reference that the GC recognizes.
            _gcHandle = GCHandle.Alloc(this);
        }

        // This is LIVE OBJECT because it has a GCHandle. The only time LIVE OBJECTS 
        // are destroyed is during Shutdown. But Shutdown cleanup is handled through 
        // the ManagedWndProcTracker and hence no work needs to happen here. PLEASE 
        // NOTE that reintroducing any cleanup logic in here will conflict with the cleanup 
        // logic in ManagedWndProcTracker and hence must be avoided. If this instance 
        // has been disposed its GCHandle is released at the time and hence this object 
        // is available for GC thereafter. Even in that case since all the cleanup has been 
        // done during dispose there is no further cleanup required.
        
        // /// <SecurityNote>
        // ///  Critical - It calls the critical DisposeImpl.
        // /// </SecurityNote>
        // [SecurityCritical]
        // ~HwndSubclass()
        // {
        //     // In Shutdown, the finalizer is called on LIVE OBJECTS.
        //     //
        //     // So this method can be called.  (even though we are pinned)
        //     // If it is, we're shutting down so it's OK to force unhooking
        //     // the subclass.
        //     DisposeImpl(true);
        // }

        /// <SecurityNote>
        ///  Critical - It calls the critical DisposeImpl.
        ///  PublicOK - Demands for AllWindows permission.
        /// </SecurityNote>
        [SecurityCritical]
        public virtual void Dispose()
        {
            SecurityHelper.DemandUIWindowPermission();

            DisposeImpl(false);
        }

        /// <SecurityNote>
        ///  Critical - Calls the critical UnhookWindowProc.
        /// </SecurityNote>
        [SecurityCritical]
        private bool DisposeImpl(bool forceUnhook)
        {
            _hook = null;

            return UnhookWindowProc(forceUnhook);
        }

        /// <summary>
        ///     This method subclasses the specified window, such that the
        ///     delegate specified to the constructor will be called to process
        ///     the messages that are sent or posted to this window.
        /// </summary>
        /// <param name="hwnd">
        ///     The window to subclass.
        /// </param>
        /// <returns>
        ///     An identifier that can be used to reference this instance of
        ///     the HwndSubclass class in the static RequestDetach method.
        /// </returns>
        /// <SecurityNote>
        ///  Critical - It calls CriticalAttach.
        ///  TreatAsSafe - Demands for AllWindows permission.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal IntPtr Attach(IntPtr hwnd)
        {
            SecurityHelper.DemandUIWindowPermission();

            if (_bond != Bond.Unattached)
                throw new InvalidOperationException(SR.Get(SRID.HwndSubclassMultipleAttach));

            return CriticalAttach( hwnd ) ;
        }


        /// <summary>
        ///     This method unsubclasses this HwndSubclass object from the window
        ///     it previously subclassed. The HwndSubclass object is not thread
        ///     safe, and should thus be called only by the thread that owns
        ///     the window being unsubclassed.
        /// </summary>
        /// <param name="force">
        ///     Whether or not the unsubclassing should be forced.  Due to the
        ///     way that Win32 implements window subclassing, it is not always
        ///     possible to safely remove a window proc from the WNDPROC chain.
        ///     However, the delegate will not be called again after this
        ///     method returns.
        /// </param>
        /// <returns>
        ///     Whether or not this HwndSubclass object was actually removed from
        ///     the WNDPROC chain.
        /// </returns>
        /// <SecurityNote>
        ///  TreatAsSafe:  Demands for all windows
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///</SecurityNote>
        [SecurityCritical]
        internal bool Detach(bool force)
        {
            SecurityHelper.DemandUIWindowPermission();

            return CriticalDetach(force);
        }

        /// <SecurityNote>
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///</SecurityNote>
        [SecurityCritical]
        internal bool CriticalDetach(bool force)
        {
            bool detached;

            // If we have already detached, return immediately.
            if(_bond == Bond.Detached || _bond == Bond.Unattached)
            {
                detached = true;
            }
            else
            {
                // When we detach, we simply make a note of it.
                _bond = Bond.Orphaned;

                // try to unhook the subclass
                detached = DisposeImpl(force);
            }

            return detached;
        }

        /// <summary>
        ///     This method sends a message to the window that is currently
        ///     subclassed by this instance of the HwndSubclass class, in order
        ///     to unsubclass the window.  This is important if a different
        ///     thread than the thread that owns the window wants to initiate
        ///     the unsubclassing.
        /// </summary>
        /// <param name="force">
        ///     Whether or not the unsubclassing should be forced.  Due to the
        ///     way that Win32 implements window subclassing, it is not always
        ///     possible to safely remove a window proc from the WNDPROC chain.
        ///     However, the delegate will not be called again after this
        ///     method returns.
        /// </param>
        /// <returns>
        ///     Nothing.
        /// </returns>
        /// <SecurityNote>
        ///  Critical - Probes _hwndAttached for value.
        ///  TreatAsSafe - The RequestDetach overload we're calling is public and safe (demands UIWindowPermission).
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal void RequestDetach(bool force)
        {
            // Let the static version do the work.
            if(_hwndAttached != IntPtr.Zero)
            {
                RequestDetach(_hwndAttached, (IntPtr) _gcHandle, force);
            }
        }

        /// <summary>
        ///     This method sends a message to the specified window in order to
        ///     cause the specified bridge to unsubclass the window.  This is
        ///     important if a different thread than the thread that owns the
        ///     window wants to initiate the unsubclassing.  The HwndSubclass
        ///     object must be identified by the value returned from Attach().
        /// </summary>
        /// <param name="hwnd">
        ///     The window to unsubclass.
        /// </param>
        /// <param name="subclass">
        ///     The identifier of the subclass to unsubclass.
        /// </param>
        /// <param name="force">
        ///     Whether or not the unsubclassing should be forced.  Due to the
        ///     way that Win32 implements window subclassing, it is not always
        ///     possible to safely remove a window proc from the WNDPROC chain.
        ///     However, the delegate will not be called again after this
        ///     method returns.
        /// </param>
        /// <returns>
        ///     Nothing.
        /// </returns>
        /// <SecurityNote>
        ///  Critical - This touches the underlying windowing infrastructure; we may want to intercept windows-messages for security-related purposes in the future.
        ///             In general we restrict access to window handles.
        ///  TreatAsSafe - Demands UIWindowPermission.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal static void RequestDetach(IntPtr hwnd, IntPtr subclass, bool force)
        {
            SecurityHelper.DemandUIWindowPermission();
            if(hwnd == IntPtr.Zero)
            {
                throw new ArgumentNullException("hwnd");
            }
            if(subclass == IntPtr.Zero)
            {
                throw new ArgumentNullException("subclass");
            }

            int iForce = force ? 1 : 0;
            UnsafeNativeMethods.UnsafeSendMessage(hwnd, DetachMessage, subclass, (IntPtr) iForce);
        }

        /// <summary>
        ///     This is the WNDPROC that gets inserted into the window's
        ///     WNDPROC chain.  It responds to various conditions that
        ///     would cause this HwndSubclass object to unsubclass the window,
        ///     and then calls the delegate specified to the HwndSubclass
        ///     constructor to process the message.  If the delegate does not
        ///     handle the message, the message is then passed on down the
        ///     WNDPROC chain for further processing.
        /// </summary>
        /// <param name="hwnd">
        ///     The window that this message was sent or posted to.
        /// </param>
        /// <param name="msg">
        ///     The message that was sent or posted.
        /// </param>
        /// <param name="wParam">
        ///     A parameter for the message that was sent or posted.
        /// </param>
        /// <param name="lParam">
        ///     A parameter for the message that was sent or posted.
        /// </param>
        /// <returns>
        ///     The value that is the result of processing the message.
        /// </returns>
        ///<SecurityNote>
        ///  Critical: this function elevates via unsafe native method calls
        ///</SecurityNote>
        [SecurityCritical]
        internal IntPtr SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
        {
            IntPtr retval = IntPtr.Zero;
            bool handled = false;
            WindowMessage message = (WindowMessage)msg;

            // If we are unattached and we receive a message, then we must have
            // been used as the original window proc.  In this case, we insert
            // ourselves as if the original window proc had been DefWindowProc.
            // We pass in DefWndProcStub as a workaround for a bug in UxTheme on
            // Windows XP. For details see the comment on the DefWndProcWrapper method.
            if(_bond == Bond.Unattached)
            {
                HookWindowProc(hwnd, new NativeMethods.WndProc(SubclassWndProc),
                    Marshal.GetFunctionPointerForDelegate(DefWndProcStub));
            }
            else if(_bond == Bond.Detached)
            {
                throw new InvalidOperationException();
            }

            IntPtr oldWndProc = _oldWndProc;    // in case we get detached during this method

            if(message == DetachMessage)
            {
                // We received our special message to detach.  Make sure it is intended
                // for us by matching the bridge.
                if(wParam == IntPtr.Zero || wParam == (IntPtr)_gcHandle)
                {
                    int param = (int)lParam;    // 0 - normal, 1 - force, 2 - force and forward
                    bool force = (param > 0);

                    retval = CriticalDetach(force) ? new IntPtr(1) : IntPtr.Zero ;
                    handled = (param < 2);
                }
            }
            else
            {
                // Pass this message to our delegate function.  Do this under
                // the exception filter/handlers of the dispatcher for this thread.
                Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
                if(dispatcher != null && !dispatcher.HasShutdownFinished)
                {
                    if (_dispatcherOperationCallback == null)
                        _dispatcherOperationCallback = new DispatcherOperationCallback(this.DispatcherCallbackOperation);

                    // _paramDispatcherCallbackOperation is a thread static member which should be reused to avoid
                    // creating a new data structure every time we call DispatcherCallbackOperation
                    // Cache the param locally in case of reentrance and set _paramDispatcherCallbackOperation to null so reentrancy calls will create a new param
                    if (_paramDispatcherCallbackOperation == null)
                        _paramDispatcherCallbackOperation = new DispatcherOperationCallbackParameter();

                    DispatcherOperationCallbackParameter param = _paramDispatcherCallbackOperation;
                    _paramDispatcherCallbackOperation = null;
                    param.hwnd = hwnd;
                    param.msg = msg;
                    param.wParam = wParam;
                    param.lParam = lParam;
                    //synchronous call
                    object result = dispatcher.Invoke(
                             DispatcherPriority.Send,
                             _dispatcherOperationCallback,
                             param);


                    if (result != null)
                    {
                        handled = param.handled;
                        retval = param.retVal;
                    }

                    // Restore _paramDispatcherCallbackOperation to the previous value so we will reuse it on the next call
                    _paramDispatcherCallbackOperation = param;
                }

                // Handle WM_NCDESTROY explicitly to forcibly clean up.
                if(message == WindowMessage.WM_NCDESTROY)
                {
                    // The fact that we received this message means that we are
                    // still in the call chain.  This is our last chance to clean
                    // up, and no other message should be received by this window
                    // proc again. It is OK to force a cleanup now.
                    CriticalDetach(true);

                    // Always pass the WM_NCDESTROY message down the chain!
                    handled = false;
                }
            }

            // If our window proc didn't handle this message, pass it on down the
            // chain.
            if(!handled)
            {
                retval = CallOldWindowProc(oldWndProc, hwnd, message, wParam, lParam);
            }

            return retval;
        }

        // Perf bug: 1963989
        // _paramDispatcherCallbackOperation is a thread static member which should be reused to avoid
        // creating a new data structure every time we DispatcherCallbackOperation is called
        // It also contains the return results (handled and retValue) from DispatcherCallbackOperation call
        /// <SecurityNote>
        ///  Critical: DispatcherOperationCallbackParameter contains hwnd, which is critical
        ///</SecurityNote>
        [SecurityCritical]
        [ThreadStatic]
        private static DispatcherOperationCallbackParameter _paramDispatcherCallbackOperation;

        // This class is used as a parameter and return result for DispatcherCallbackOperation call
        private class DispatcherOperationCallbackParameter
        {
            internal IntPtr hwnd, wParam, lParam, retVal;
            internal int msg;
            internal bool handled;
        }

        private DispatcherOperationCallback _dispatcherOperationCallback = null;

        /// <SecurityNote>
        ///  Critical: it calls GetWindowLongPtr(), which is Critical
        ///</SecurityNote>
        [ SecurityCritical ]
        internal IntPtr CriticalAttach( IntPtr hwnd )
        {
            if(hwnd == IntPtr.Zero)
            {
                throw new ArgumentNullException("hwnd");
            }
            if(_bond != Bond.Unattached)
            {
                throw new InvalidOperationException();
            }

            NativeMethods.WndProc newWndProc = new NativeMethods.WndProc(SubclassWndProc);
            IntPtr oldWndProc = UnsafeNativeMethods.GetWindowLongPtr(new HandleRef(this,hwnd), NativeMethods.GWL_WNDPROC);
            HookWindowProc(hwnd, newWndProc, oldWndProc);

            // Return the GC handle as a unique identifier of this
            return (IntPtr) _gcHandle;
        }

        /// <SecurityNote>
        ///     Critical: This code is a callback into the dispatcher. It is present
        ///      because under enforcements anonymous delagates throw a demand since
        ///      it becomes a transparent calling critical for this particular call
        /// </SecurityNote>
        [SecurityCritical]
        private object DispatcherCallbackOperation(object o)
        {
            DispatcherOperationCallbackParameter param = (DispatcherOperationCallbackParameter)o;
            param.handled = false;
            param.retVal = IntPtr.Zero;
            if (_bond == Bond.Attached)
            {
                HwndWrapperHook hook= _hook.Target as HwndWrapperHook;

                if (hook != null)
                {
                    // make the call
                    param.retVal = hook(param.hwnd, param.msg, param.wParam, param.lParam, ref param.handled);
                }
            }

            return param;
        }

        /// <summary>
        ///     This method lets the user call the old WNDPROC, i.e
        ///     the next WNDPROC in the chain directly.
        /// </summary>
        /// <param name="oldWndProc">
        ///     The WndProc to call.
        /// </param>
        /// <param name="hwnd">
        ///     The window that this message was sent or posted to.
        /// </param>
        /// <param name="msg">
        ///     The message that was sent or posted.
        /// </param>
        /// <param name="wParam">
        ///     A parameter for the message that was sent or posted.
        /// </param>
        /// <param name="lParam">
        ///     A parameter for the message that was sent or posted.
        /// </param>
        /// <returns>
        ///     The value that is the result of processing the message.
        /// </returns>
        /// <SecurityNote>
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///</SecurityNote>
        [SecurityCritical]
        IntPtr CallOldWindowProc(IntPtr oldWndProc, IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            return UnsafeNativeMethods.CallWindowProc(oldWndProc, hwnd, (int)msg, wParam, lParam);
        }

        ///<SecurityNote>
        /// Critical - it calls CriticalSetWindowLong()
        ///</SecurityNote>
        [SecurityCritical]
        private void HookWindowProc(IntPtr hwnd, NativeMethods.WndProc newWndProc, IntPtr oldWndProc)
        {
            _hwndAttached = hwnd;
            _hwndHandleRef = new HandleRef(null,_hwndAttached);
            _bond = Bond.Attached;

            _attachedWndProc = newWndProc;
            _oldWndProc = oldWndProc;
            IntPtr oldWndProc2 = (IntPtr)UnsafeNativeMethods.CriticalSetWindowLong(_hwndHandleRef, NativeMethods.GWL_WNDPROC, _attachedWndProc);

            // Track this window so that we can rip out the managed window proc
            // when the CLR shuts down.
            ManagedWndProcTracker.TrackHwndSubclass(this, _hwndAttached);
        }

        // This method should only be called from Dispose. Otherwise assumptions about the disposing/finalize state could be violated.
        // force - when true, remove this subclass from the WndProc chain regardless of
        //          its current position.  When false, remove this subclass only
        //          if it is possible to do so without damaging other WndProcs
        //          (i.e. only if this is at the head of the chain).
        //
        // Removing this subclass from the WndProc chain when it is not at the head
        // also removes all other WndProcs that appear before this one on the chain,
        // so is generally not appropriate. It is OK in the following situations:
        //  a) in response to the WM_NCDESTROY message
        //  b) in response to the AppDomainProcessExit event
        //  c) in response to the AppDomainExit event
        // In cases (a) and (b) the HWND is being destroyed, so the earlier
        // WndProcs are no longer useful anyway.  In case (c), we have to remove
        // all managed code from the chain lest it be called after it has been
        // removed from memory;  removing earlier WndProcs is unfortunate, but
        // necessary.  [Note that at AppDomainExit we remove all managed WndProcs,
        // regardless of which AppDomain they came from.  There is room for
        // improvement here - we could remove only the ones belong to the AppDomain
        // that is exiting.  This situation seems too unlikely to worry about in V1.]
        //
        // This method returns true if the subclass is no longer in the WndProc chain.
        //
        /// <SecurityNote>
        ///  Critical - Calls CriticalSetWindowLong() and GetWindowLongWndProc().
        ///             This touches the underlying windowing infrastructure; we may want to intercept windows-messages for security-related purposes in the future.
        ///             In general we restrict access to window handles.
        /// </SecurityNote>
        [SecurityCritical]
        private bool UnhookWindowProc(bool force)
        {
            // if we're not in the WndProc chain, there's nothing to do
            if (_bond == Bond.Unattached || _bond == Bond.Detached)
            {
                return true;
            }

            // we'll remove ourselves from the chain if we're at the head, or if
            // the 'force' parameter was true.
            if (!force)
            {
                NativeMethods.WndProc currentWndProc = UnsafeNativeMethods.GetWindowLongWndProc(new HandleRef(this,_hwndAttached));
                force = (currentWndProc == _attachedWndProc);
            }

            // if we're not unhooking, return and report
            if (!force)
            {
                return false;
            }

            // unhook from the tracker
            _bond = Bond.Orphaned;  // ignore messages while we're unhooking
            ManagedWndProcTracker.UnhookHwndSubclass(this);

            // unhook, the Win32 way
            try
            {
                UnsafeNativeMethods.CriticalSetWindowLong(_hwndHandleRef, NativeMethods.GWL_WNDPROC, _oldWndProc);
            }
            catch (System.ComponentModel.Win32Exception e)
            {
                if (e.NativeErrorCode != 1400) // ERROR_INVALID_WINDOW_HANDLE
                {
                    throw;
                }
            }


            // clear our state
            _bond = Bond.Detached;

            _oldWndProc = IntPtr.Zero;
            _attachedWndProc = null;
            _hwndAttached = IntPtr.Zero;
            _hwndHandleRef = new HandleRef(null,IntPtr.Zero);

            // un-Pin this object.
            // Note: the GC is free to collect this object at anytime
            // after we have freed this handle - that is, once all
            // other managed references go away.

            //AvDebug.Assert(_gcHandle.IsAllocated, "External GC handle has not been allocated.");

            if(null != _gcHandle)
                _gcHandle.Free();

            return true;
        }




        /// <summary>
        /// DefWndProcWrapper is a wrapper around DefWndProc.  This is a workaround
        /// for WindowsSE bugs 124461 and 124455, which affect Windows XP SP2, Luna theme.
        ///
        /// HwndSubclass.SubclassWndProc is sometimes directly set as the window proc of a
        /// Window (HwndWrapper's constructor does this).  When this happens it subclasses
        /// itself on the first message it receives. Since the old window proc is itself,
        /// it saves off DefWndProc as the old window proc instead.
        ///
        /// As described by the bugs and and KB article 319740, if we set DefWndProc
        /// as the window proc of the window, we'll leak 6 GDI region objects
        /// corresponding to the Luna-themed non-client area.
        ///
        /// The reason for this is that the kernel will flag that window as a server-side
        /// window. If the WndProc replacement happens in response to a WM_NCDESTROY message
        /// (as it does in the case where Avalon is creating and closing windows), the Shell
        /// won't clean up the regions.
        ///
        /// The fix is slated for XP SP3, so for now WPF is implementing a workaround:
        /// if we set the window proc to be a stub that calls into DefWndProc, the kernel
        /// won't set us as a server-side window.
        /// </summary>
        /// <SecurityNote>
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///</SecurityNote>
        [SecurityCritical]
        private static IntPtr DefWndProcWrapper(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
        {
            return UnsafeNativeMethods.CallWindowProc(DefWndProc, hwnd, msg, wParam, lParam);
        }



        // Message to cause a detach.
        //      WPARAM=IntPtr returned from Attach(), or 0 to match all subclasses.
        //      LPARAM= 0 - normal (unhook subclass if it is first on the chain)
        //              1 - force unhooking subclass from the chain
        //              2 - force, and forward message to next WndProc
        internal static readonly WindowMessage DetachMessage;

        private enum Bond
        {
            Unattached,
            Attached,
            Detached,
            Orphaned
        }


        /// <summary>
        /// This is a delegate that points to DefWndProcWrapper.  It is set into
        /// a Window's WndProc instead of DefWndProc in order to work around a bug.
        /// See the comment on DefWndProcWrapper.
        ///
        /// By instantiating this delegate as a static variable we ensure that
        /// it will remain alive long enough to process messages.
        /// </summary>
        /// <SecurityNote>
        ///     Critical: This will expose DefWndProc
        /// </SecurityNote>
        [SecurityCritical]
        private static NativeMethods.WndProc DefWndProcStub = new NativeMethods.WndProc(DefWndProcWrapper);

        /// <SecurityNote>
        ///     Critical: This will expose wndproc
        /// </SecurityNote>
        [SecurityCritical]
        private static IntPtr DefWndProc;

        /// <SecurityNote>
        ///     Critical: This will expose the intptr of the window
        /// </SecurityNote>
        [SecurityCritical]
        private IntPtr _hwndAttached;
        /// <SecurityNote>
        ///     Critical: This will expose window handle
        /// </SecurityNote>
        [SecurityCritical]
        private HandleRef _hwndHandleRef;
        /// <SecurityNote>
        ///     Critical: This will expose wndproc
        /// </SecurityNote>
        [SecurityCritical]
        private NativeMethods.WndProc _attachedWndProc;
        /// <SecurityNote>
        ///     Critical: This will expose wndproc
        /// </SecurityNote>
        [SecurityCritical]
        private IntPtr                _oldWndProc;
        private Bond                  _bond;
        private GCHandle              _gcHandle;
        /// <SecurityNote>
        ///     Critical: This will expose hook
        /// </SecurityNote>
        [SecurityCritical]
        private WeakReference _hook;
    };
}

