// 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); }