dotnet/wpf · error · ArgumentNullException

ArgumentNullException

Error message

ArgumentNullException

What it means

The second validation in HwndSubclass.RequestDetach: the 'subclass' parameter must be a non-zero IntPtr identifying the subclass instance. Passing IntPtr.Zero throws ArgumentNullException for subclass.

Solutions

  1. Pass the original non-zero subclass IntPtr (the gcHandle) used at attach time
  2. Guard with if (subclass != IntPtr.Zero) before calling RequestDetach
  3. Keep the subclass handle alive until detach completes; avoid clearing it during teardown

Example fix

// before
HwndSubclass.RequestDetach(hwnd, IntPtr.Zero, true);
// after
if (_subclass != IntPtr.Zero) HwndSubclass.RequestDetach(hwnd, _subclass, true);
Defensive patterns

Strategy: validation

Validate before calling

if (hwnd == IntPtr.Zero || subclass == IntPtr.Zero) return;
HwndSubclass.RequestDetach(hwnd, subclass, force);

Type guard

bool CanRequestDetach(IntPtr hwnd, IntPtr subclass) => hwnd != IntPtr.Zero && subclass != IntPtr.Zero;

Try / catch

try { HwndSubclass.RequestDetach(hwnd, subclass, force); } catch (ArgumentNullException ex) when (ex.ParamName == "subclass") { /* subclass reference lost; nothing to detach */ }

Prevention

When it happens

Trigger: Calling HwndSubclass.RequestDetach(hwnd, IntPtr.Zero, force) — a zero handle where the subclass (gcHandle wrapper) reference is required.

Common situations: The subclass reference field was never initialized or was cleared before detach; passing default(IntPtr) as a placeholder; race where detach runs after the wrapper reset its fields.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/6bddc1777047d20a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndSubclass.cs:227

        /// <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>
        internal static void RequestDetach(IntPtr hwnd, IntPtr subclass, bool force)
        {
            if(hwnd == IntPtr.Zero)
            {
                throw new ArgumentNullException(nameof(hwnd));
            }
            if(subclass == IntPtr.Zero)
            {
                throw new ArgumentNullException(nameof(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>

View on GitHub (pinned to 81131a70a4)