Ejemplo n.º 1
0
        // 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.
        //
        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);
        }