dotnet/wpf · error · ArgumentException

SR.HwndTarget_InvalidWindowThread

Error message

SR.HwndTarget_InvalidWindowThread

What it means

The target window must also belong to the calling thread: AttachToHwnd compares the hwnd's thread id with GetCurrentThreadId() and throws ArgumentException (SR.HwndTarget_InvalidWindowThread) on mismatch. WPF rendering targets are thread-affine, so the window must live on the thread creating the HwndTarget.

Solutions

  1. Create the HwndSource on the same thread that created the HWND
  2. Marshal construction to the window's owning thread via Dispatcher.BeginInvoke
  3. If using a dedicated UI thread, create the window handle on that same thread

Example fix

// before
Task.Run(() => new HwndSource(0, 0, 0, 0, 0, "x", uiThreadHwnd)); // throws
// after
dispatcherOfOwningThread.Invoke(() => new HwndSource(0, 0, 0, 0, 0, "x", hwnd));
Defensive patterns

Strategy: validation

Validate before calling

GetWindowThreadProcessId(hwnd, out _);
if (threadId != SafeNativeMethods.GetCurrentThreadId()) Marshal to owning thread before creating the source;

Type guard

bool IsOnCurrentThread(IntPtr hwnd) => GetWindowThreadId(hwnd) == SafeNativeMethods.GetCurrentThreadId();

Try / catch

try { new HwndSource(...); } catch (ArgumentException) { /* dispatch to owning thread's Dispatcher */ }

Prevention

When it happens

Trigger: Constructing an HwndSource/HwndTarget on thread B for an HWND created on thread A (e.g. building UI on a background/worker thread using a handle created by the UI thread).

Common situations: Multi-threaded apps creating windows on the main thread but initializing WPF interop content on a worker; COM/threading mismatches in mixed Win32/WPF apps.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs:538

                );

            if (!UnsafeNativeMethods.IsWindow(new HandleRef(this, hwnd)))
            {
                throw new ArgumentException(
                    SR.HwndTarget_InvalidWindowHandle,
                    nameof(hwnd)
                    );
            }
            else if (processId != Environment.ProcessId)
            {
                throw new ArgumentException(
                    SR.HwndTarget_InvalidWindowProcess,
                    nameof(hwnd)
                    );
            }
            else if (threadId != SafeNativeMethods.GetCurrentThreadId())
            {
                throw new ArgumentException(
                    SR.HwndTarget_InvalidWindowThread,
                    nameof(hwnd)
                    );
            }

            int hr = VisualTarget_AttachToHwnd(hwnd);

            if (HRESULT.Failed(hr))
            {
                if (hr == unchecked((int)0x80070005)) // E_ACCESSDENIED
                {
                    throw new InvalidOperationException(
                        SR.HwndTarget_WindowAlreadyHasContent
                        );
                }
                else
                {
                    HRESULT.Check(hr);

View on GitHub (pinned to 81131a70a4)