dotnet/wpf · error · ArgumentNullException

throw new ArgumentNullException(nameof(hwnd));

Error message

throw new ArgumentNullException(nameof(hwnd));

What it means

HwndSubclass.RequestDetach sends a special message to the window to locate and detach the given subclass. It validates inputs: an IntPtr.Zero hwnd cannot receive a message, so it throws ArgumentNullException for hwnd.

Solutions

  1. Verify hwnd != IntPtr.Zero before calling RequestDetach
  2. Skip detach if the window handle is already destroyed/zero (detach is then moot)
  3. Store the HWND in a checked property rather than a raw field that can become Zero

Example fix

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

Strategy: validation

Validate before calling

if (hwnd == IntPtr.Zero) return; // window already gone; nothing to detach
HwndSubclass.RequestDetach(hwnd, subclass, force);

Type guard

bool IsValidWindowHandle(IntPtr hwnd) => hwnd != IntPtr.Zero;

Try / catch

try { HwndSubclass.RequestDetach(hwnd, subclass, force); } catch (ArgumentNullException ex) when (ex.ParamName == "hwnd") { /* handle already destroyed; skip */ }

Prevention

When it happens

Trigger: Calling HwndSubclass.RequestDetach(IntPtr.Zero, subclass, force) — passing a zero handle as the target window.

Common situations: Caching an HWND after the window was destroyed (handle resets to Zero); using a default-initialized IntPtr; detaching during shutdown after handle teardown.

Related errors


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

Appendix: source

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

        /// </param>
        /// <param name="subclass">
        ///     The identifier of the subclass to unsubclass.
        /// </param>
        /// <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.

View on GitHub (pinned to 81131a70a4)