/// <summary> /// Subclasses the window. /// </summary> /// <remarks> /// You must call <see cref="Dispose()"/> to undo the subclassing before /// the window is destroyed. /// </remarks> /// <returns></returns> public void Open() { if (_disposed) { throw new ObjectDisposedException(nameof(WindowSubclassHandler)); } if (_opened) { throw new InvalidOperationException(); } // Replace the existing window procedure with our one // ("instance subclassing"). // We need to explicitely clear the last Win32 error and then retrieve // it, to check if the call succeeded. WindowSubclassHandlerNativeMethods.SetLastError(0); _originalWindowProc = WindowSubclassHandlerNativeMethods.SetWindowLongPtr( _handle, WindowSubclassHandlerNativeMethods.GWLP_WNDPROC, _windowProcDelegatePtr); if (_originalWindowProc == IntPtr.Zero && Marshal.GetLastWin32Error() != 0) { throw new Win32Exception(); } Debug.Assert(_originalWindowProc != _windowProcDelegatePtr); _opened = true; }
protected virtual void Dispose(bool disposing) { if (!_disposed) { // We cannot do anything from the finalizer thread since we have // resoures that must only be accessed from the GUI thread. if (disposing && _opened) { // Check if the current window procedure is the correct one. // We need to explicitely clear the last Win32 error and then // retrieve it, to check if the call succeeded. WindowSubclassHandlerNativeMethods.SetLastError(0); IntPtr currentWindowProcedure = WindowSubclassHandlerNativeMethods.GetWindowLongPtr( _handle, WindowSubclassHandlerNativeMethods.GWLP_WNDPROC); if (currentWindowProcedure == IntPtr.Zero && Marshal.GetLastWin32Error() != 0) { throw new Win32Exception(); } if (currentWindowProcedure != _windowProcDelegatePtr) { throw new InvalidOperationException( "The current window procedure is not the expected one."); } // Undo the subclassing by restoring the original window // procedure. WindowSubclassHandlerNativeMethods.SetLastError(0); if (WindowSubclassHandlerNativeMethods.SetWindowLongPtr( _handle, WindowSubclassHandlerNativeMethods.GWLP_WNDPROC, _originalWindowProc) == IntPtr.Zero && Marshal.GetLastWin32Error() != 0) { throw new Win32Exception(); } // Ensure to keep the delegate alive up to the point after we // have undone the subclassing. KeepCallbackDelegateAlive(); } _disposed = true; } }