{"record":{"id":"b325bd7bd343bff0","repo":"dotnet/wpf","slug":"sr-hwndtarget-invalidwindowthread","errorCode":null,"errorMessage":"SR.HwndTarget_InvalidWindowThread","messagePattern":"SR\\.HwndTarget_InvalidWindowThread","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs","lineNumber":538,"sourceCode":"                );\n\n            if (!UnsafeNativeMethods.IsWindow(new HandleRef(this, hwnd)))\n            {\n                throw new ArgumentException(\n                    SR.HwndTarget_InvalidWindowHandle,\n                    nameof(hwnd)\n                    );\n            }\n            else if (processId != Environment.ProcessId)\n            {\n                throw new ArgumentException(\n                    SR.HwndTarget_InvalidWindowProcess,\n                    nameof(hwnd)\n                    );\n            }\n            else if (threadId != SafeNativeMethods.GetCurrentThreadId())\n            {\n                throw new ArgumentException(\n                    SR.HwndTarget_InvalidWindowThread,\n                    nameof(hwnd)\n                    );\n            }\n\n            int hr = VisualTarget_AttachToHwnd(hwnd);\n\n            if (HRESULT.Failed(hr))\n            {\n                if (hr == unchecked((int)0x80070005)) // E_ACCESSDENIED\n                {\n                    throw new InvalidOperationException(\n                        SR.HwndTarget_WindowAlreadyHasContent\n                        );\n                }\n                else\n                {\n                    HRESULT.Check(hr);","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndTarget.cs#L520-L556","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Create the HwndSource on the same thread that created the HWND","Marshal construction to the window's owning thread via Dispatcher.BeginInvoke","If using a dedicated UI thread, create the window handle on that same thread"],"exampleFix":"// before\nTask.Run(() => new HwndSource(0, 0, 0, 0, 0, \"x\", uiThreadHwnd)); // throws\n// after\ndispatcherOfOwningThread.Invoke(() => new HwndSource(0, 0, 0, 0, 0, \"x\", hwnd));","handlingStrategy":"validation","validationCode":"GetWindowThreadProcessId(hwnd, out _);\nif (threadId != SafeNativeMethods.GetCurrentThreadId()) Marshal to owning thread before creating the source;","typeGuard":"bool IsOnCurrentThread(IntPtr hwnd) => GetWindowThreadId(hwnd) == SafeNativeMethods.GetCurrentThreadId();","tryCatchPattern":"try { new HwndSource(...); } catch (ArgumentException) { /* dispatch to owning thread's Dispatcher */ }","preventionTips":["Create HwndSource on the same thread that owns the HWND","Keep all WPF interop setup on a single Dispatcher thread","Avoid Task.Run around window/handle creation"],"tags":["wpf","interop","threading","hwnd"],"backgroundTag":"invalid-argument-value","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}