Skip to content

Fix XamlMessageBox STA Threading Crash from Background Threads#2400

Merged
brianrob merged 3 commits intomicrosoft:mainfrom
brianrob:brianrob/issue-2300
Mar 27, 2026
Merged

Fix XamlMessageBox STA Threading Crash from Background Threads#2400
brianrob merged 3 commits intomicrosoft:mainfrom
brianrob:brianrob/issue-2300

Conversation

@brianrob
Copy link
Copy Markdown
Member

Summary

Fixes #2300XamlMessageBox.Show() now auto-dispatches to the UI thread when called from a background thread, matching the old System.Windows.MessageBox behavior.

Problem

PR #2276 replaced System.Windows.MessageBox (Win32 API, no thread affinity) with XamlMessageBox (WPF ShowDialog(), requires STA/UI thread). Several call sites invoke XamlMessageBox.Show() from background threads — most notably the SecurityCheck delegate in App.cs, which runs during symbol resolution on Task.Run threads. This causes:

System.InvalidOperationException: The calling thread must be STA, because many UI components require this.

Fix

Added auto-dispatch logic to the core XamlMessageBox.Show() overload (all 10+ overloads funnel through this single method):

  • Checks owner?.Dispatcher ?? Application.Current?.Dispatcher
  • If the current thread doesn't own the dispatcher (!CheckAccess()), uses synchronous Dispatcher.Invoke to marshal the call
  • Prefers the owner window's dispatcher when provided, falling back to the Application dispatcher
  • No-op when already on the correct thread — existing UI-thread call sites are unaffected

Testing

  • Added XamlMessageBoxTests.cs with a regression test that exercises both UI-thread and background-thread Show() calls
  • Test creates a WPF Application on a dedicated STA thread, uses EventManager.RegisterClassHandler to auto-close dialogs, and verifies no exceptions are thrown
  • All existing PerfView.Tests continue to pass

@brianrob brianrob requested a review from a team as a code owner March 27, 2026 18:19
brianrob and others added 3 commits March 27, 2026 11:22
XamlMessageBox.Show() now auto-dispatches to the UI thread when called
from a background thread, matching the old System.Windows.MessageBox
behavior. This fixes the SecurityCheck delegate crash during symbol
resolution, where the delegate is invoked on Task.Run threads.

The fix checks Application.Current.Dispatcher.CheckAccess() and uses
synchronous Dispatcher.Invoke to marshal the call, preserving the
return value for callers. Existing UI-thread call sites are unaffected
(CheckAccess returns true, no dispatch needed).

Fixes microsoft#2300

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ingleton, guard RegisterClassHandler

- XamlMessageBox.cs: Use owner?.Dispatcher ?? Application.Current?.Dispatcher
  so the dispatch targets the correct UI thread when an owner window is provided.
  Simplify with Dispatcher.Invoke(Func<T>) to return result directly.
- XamlMessageBoxTests.cs: Guard Application creation with Application.Current ??
  to prevent InvalidOperationException in shared AppDomains.
- XamlMessageBoxTests.cs: Add static guard for RegisterClassHandler (permanent,
  AppDomain-wide registration) and use XamlMBTest_ prefix for unique captions.
- XamlMessageBoxTests.cs: Use indexer assignment for theme resources (idempotent).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…spatcher in test

Replace app.Dispatcher.BeginInvoke with Dispatcher.CurrentDispatcher.BeginInvoke
to ensure work is queued to the dispatcher being pumped by Dispatcher.Run().
If Application.Current was reused from a prior test on a different thread,
app.Dispatcher would target that thread's dispatcher, causing the test to hang.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@brianrob brianrob force-pushed the brianrob/issue-2300 branch from 1825169 to 36558d0 Compare March 27, 2026 18:23
@brianrob brianrob enabled auto-merge (squash) March 27, 2026 18:32
@brianrob brianrob merged commit 5ef79ab into microsoft:main Mar 27, 2026
5 checks passed
@brianrob brianrob deleted the brianrob/issue-2300 branch March 27, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Symbols for my own code not found due to "The calling thread must be STA, because many UI components require this."

2 participants