HwndSubclass.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Shared / MS / Win32 / HwndSubclass.cs / 1 / HwndSubclass.cs

                            using System; 
using System.Runtime.InteropServices;
using System.Security.Permissions;
using MS.Internal;
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 
{ 
    /// 
    ///     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. 
    /// 
    ///  Not available to partial trust callers
    [FriendAccessAllowed] // Built into Base, also used by Framework
    internal class HwndSubclass : IDisposable 
    {
        ///  
        ///  Critical: Elevates by calling an UnsafeNativeMethod 
        ///
        [SecurityCritical] 
        static HwndSubclass()
        {
            DetachMessage = UnsafeNativeMethods.RegisterWindowMessage("HwndSubclass.DetachMessage");
            if (DetachMessage == 0) 
            {
                throw new System.ComponentModel.Win32Exception(); 
            } 

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

            DefWndProc = address; 
        }
 
        ///  
        ///     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.
        /// 
        /// 
        ///     The delegate that will be called to process the messages that 
        ///     are sent or posted to the window.
        ///  
        ///  
        ///     Nothing.
        ///  
        /// 
        ///  Critical: This code creates an object that is not allowed in partial trust
        /// 
        [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.

        // ///  
        // ///  Critical - It calls the critical DisposeImpl.
        // ///  
        // [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); 
        // } 

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

            DisposeImpl(false); 
        }

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

            return UnhookWindowProc(forceUnhook);
        }
 
        /// 
        ///     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.
        ///  
        /// 
        ///     The window to subclass.
        /// 
        ///  
        ///     An identifier that can be used to reference this instance of
        ///     the HwndSubclass class in the static RequestDetach method. 
        ///  
        /// 
        ///  Critical - It calls CriticalAttach. 
        ///  TreatAsSafe - Demands for AllWindows permission.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal IntPtr Attach(IntPtr hwnd) 
        {
            SecurityHelper.DemandUIWindowPermission(); 
 
            if (_bond != Bond.Unattached)
                throw new InvalidOperationException(SR.Get(SRID.HwndSubclassMultipleAttach)); 

            return CriticalAttach( hwnd ) ;
        }
 

        ///  
        ///     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.
        /// 
        /// 
        ///     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.
        ///  
        /// 
        ///     Whether or not this HwndSubclass object was actually removed from
        ///     the WNDPROC chain.
        ///  
        /// 
        ///  TreatAsSafe:  Demands for all windows 
        ///  Critical: Elevates by calling an UnsafeNativeMethod 
        ///
        [SecurityCritical] 
        internal bool Detach(bool force)
        {
            SecurityHelper.DemandUIWindowPermission();
 
            return CriticalDetach(force);
        } 
 
        /// 
        ///  Critical: Elevates by calling an UnsafeNativeMethod 
        ///
        [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;
        } 

        ///  
        ///     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.
        /// 
        ///  
        ///     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. 
        /// 
        /// 
        ///     Nothing.
        ///  
        /// 
        ///  Critical - Probes _hwndAttached for value. 
        ///  TreatAsSafe - The RequestDetach overload we're calling is public and safe (demands UIWindowPermission). 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void RequestDetach(bool force)
        {
            // Let the static version do the work.
            if(_hwndAttached != IntPtr.Zero) 
            {
                RequestDetach(_hwndAttached, (IntPtr) _gcHandle, force); 
            } 
        }
 
        /// 
        ///     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(). 
        ///  
        /// 
        ///     The window to unsubclass. 
        /// 
        /// 
        ///     The identifier of the subclass to unsubclass.
        ///  
        /// 
        ///     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.
        /// 
        /// 
        ///     Nothing. 
        /// 
        ///  
        ///  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. 
        /// 
        [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); 
        }
 
        /// 
        ///     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.
        ///  
        /// 
        ///     The window that this message was sent or posted to.
        /// 
        ///  
        ///     The message that was sent or posted.
        ///  
        ///  
        ///     A parameter for the message that was sent or posted.
        ///  
        /// 
        ///     A parameter for the message that was sent or posted.
        /// 
        ///  
        ///     The value that is the result of processing the message.
        ///  
        /// 
        ///  Critical: this function elevates via unsafe native method calls
        /// 
        [SecurityCritical]
        internal IntPtr SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
        {
            IntPtr retval = IntPtr.Zero; 
            bool handled = false;
 
            // 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(msg == 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(msg == NativeMethods.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, msg, 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 
        /// 
        ///  Critical: DispatcherOperationCallbackParameter contains hwnd, which is critical 
        /// 
        [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;

        ///  
        ///  Critical: it calls GetWindowLongPtr(), which is Critical
        /// 
        [ 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; 
        } 

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

        ///
        /// Critical - it calls CriticalSetWindowLong()
        /// 
        [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. 
        // 
        /// 
        ///  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.
        /// 
        [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; 
        }


 

        ///  
        /// 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.
        ///  
        /// 
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///
        [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 int DetachMessage;
 
        private enum Bond
        {
            Unattached,
            Attached, 
            Detached,
            Orphaned 
        } 

 
        /// 
        /// 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. 
        /// 
        ///  
        ///     Critical: This will expose DefWndProc
        /// 
        [SecurityCritical]
        private static NativeMethods.WndProc DefWndProcStub = new NativeMethods.WndProc(DefWndProcWrapper); 

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

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


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System; 
using System.Runtime.InteropServices;
using System.Security.Permissions;
using MS.Internal;
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 
{ 
    /// 
    ///     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. 
    /// 
    ///  Not available to partial trust callers
    [FriendAccessAllowed] // Built into Base, also used by Framework
    internal class HwndSubclass : IDisposable 
    {
        ///  
        ///  Critical: Elevates by calling an UnsafeNativeMethod 
        ///
        [SecurityCritical] 
        static HwndSubclass()
        {
            DetachMessage = UnsafeNativeMethods.RegisterWindowMessage("HwndSubclass.DetachMessage");
            if (DetachMessage == 0) 
            {
                throw new System.ComponentModel.Win32Exception(); 
            } 

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

            DefWndProc = address; 
        }
 
        ///  
        ///     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.
        /// 
        /// 
        ///     The delegate that will be called to process the messages that 
        ///     are sent or posted to the window.
        ///  
        ///  
        ///     Nothing.
        ///  
        /// 
        ///  Critical: This code creates an object that is not allowed in partial trust
        /// 
        [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.

        // ///  
        // ///  Critical - It calls the critical DisposeImpl.
        // ///  
        // [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); 
        // } 

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

            DisposeImpl(false); 
        }

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

            return UnhookWindowProc(forceUnhook);
        }
 
        /// 
        ///     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.
        ///  
        /// 
        ///     The window to subclass.
        /// 
        ///  
        ///     An identifier that can be used to reference this instance of
        ///     the HwndSubclass class in the static RequestDetach method. 
        ///  
        /// 
        ///  Critical - It calls CriticalAttach. 
        ///  TreatAsSafe - Demands for AllWindows permission.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal IntPtr Attach(IntPtr hwnd) 
        {
            SecurityHelper.DemandUIWindowPermission(); 
 
            if (_bond != Bond.Unattached)
                throw new InvalidOperationException(SR.Get(SRID.HwndSubclassMultipleAttach)); 

            return CriticalAttach( hwnd ) ;
        }
 

        ///  
        ///     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.
        /// 
        /// 
        ///     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.
        ///  
        /// 
        ///     Whether or not this HwndSubclass object was actually removed from
        ///     the WNDPROC chain.
        ///  
        /// 
        ///  TreatAsSafe:  Demands for all windows 
        ///  Critical: Elevates by calling an UnsafeNativeMethod 
        ///
        [SecurityCritical] 
        internal bool Detach(bool force)
        {
            SecurityHelper.DemandUIWindowPermission();
 
            return CriticalDetach(force);
        } 
 
        /// 
        ///  Critical: Elevates by calling an UnsafeNativeMethod 
        ///
        [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;
        } 

        ///  
        ///     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.
        /// 
        ///  
        ///     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. 
        /// 
        /// 
        ///     Nothing.
        ///  
        /// 
        ///  Critical - Probes _hwndAttached for value. 
        ///  TreatAsSafe - The RequestDetach overload we're calling is public and safe (demands UIWindowPermission). 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void RequestDetach(bool force)
        {
            // Let the static version do the work.
            if(_hwndAttached != IntPtr.Zero) 
            {
                RequestDetach(_hwndAttached, (IntPtr) _gcHandle, force); 
            } 
        }
 
        /// 
        ///     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(). 
        ///  
        /// 
        ///     The window to unsubclass. 
        /// 
        /// 
        ///     The identifier of the subclass to unsubclass.
        ///  
        /// 
        ///     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.
        /// 
        /// 
        ///     Nothing. 
        /// 
        ///  
        ///  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. 
        /// 
        [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); 
        }
 
        /// 
        ///     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.
        ///  
        /// 
        ///     The window that this message was sent or posted to.
        /// 
        ///  
        ///     The message that was sent or posted.
        ///  
        ///  
        ///     A parameter for the message that was sent or posted.
        ///  
        /// 
        ///     A parameter for the message that was sent or posted.
        /// 
        ///  
        ///     The value that is the result of processing the message.
        ///  
        /// 
        ///  Critical: this function elevates via unsafe native method calls
        /// 
        [SecurityCritical]
        internal IntPtr SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
        {
            IntPtr retval = IntPtr.Zero; 
            bool handled = false;
 
            // 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(msg == 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(msg == NativeMethods.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, msg, 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 
        /// 
        ///  Critical: DispatcherOperationCallbackParameter contains hwnd, which is critical 
        /// 
        [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;

        ///  
        ///  Critical: it calls GetWindowLongPtr(), which is Critical
        /// 
        [ 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; 
        } 

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

        ///
        /// Critical - it calls CriticalSetWindowLong()
        /// 
        [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. 
        // 
        /// 
        ///  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.
        /// 
        [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; 
        }


 

        ///  
        /// 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.
        ///  
        /// 
        ///  Critical: Elevates by calling an UnsafeNativeMethod
        ///
        [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 int DetachMessage;
 
        private enum Bond
        {
            Unattached,
            Attached, 
            Detached,
            Orphaned 
        } 

 
        /// 
        /// 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. 
        /// 
        ///  
        ///     Critical: This will expose DefWndProc
        /// 
        [SecurityCritical]
        private static NativeMethods.WndProc DefWndProcStub = new NativeMethods.WndProc(DefWndProcWrapper); 

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

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


// 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