{"record":{"id":"594ad1c6d4252fcf","repo":"dotnet/wpf","slug":"sr-cantshowondifferentthread","errorCode":null,"errorMessage":"SR.CantShowOnDifferentThread","messagePattern":"SR\\.CantShowOnDifferentThread","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs","lineNumber":232,"sourceCode":"            }\n            return IntPtr.Zero;\n        }\n\n        /// <summary>\n        ///  When overridden in a derived class, displays a particular type of common dialog box.\n        /// </summary>\n        protected abstract bool RunDialog(IntPtr hwndOwner);\n\n        /// <summary>\n        ///  Demands permissions appropriate to the dialog to be shown.\n        /// </summary>\n        protected virtual void CheckPermissionsToShowDialog()\n        {\n            // Verify we're on the right thread.  \n            // This mitigates multi-threaded attacks without having to make the file dialogs thread-safe.\n            if (_thread != Thread.CurrentThread)\n            {\n                throw new InvalidOperationException(SR.CantShowOnDifferentThread);\n            }\n\n        }\n\n        #endregion Protected Methods\n\n        //---------------------------------------------------\n        //\n        // Internal Methods\n        //\n        //---------------------------------------------------\n        #region Internal Methods\n\n        // This method is not used by IFileDialog API. Kept for compatibility (see HookProc).\n        /// <summary>\n        ///  Centers the given window on the screen. This method is used by HookProc\n        ///  to center the dialog on the screen before it is shown.\n        /// </summary>","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs#L214-L250","documentation":"CommonDialog.CheckPermissionsToShowDialog verifies the calling thread matches the thread that constructed the dialog (_thread captured in the constructor). Showing the dialog from a different thread is blocked to mitigate multi-threaded attacks and because the dialogs are not thread-safe.","triggerScenarios":"Creating a Win32 OpenFileDialog/SaveFileDialog on thread A (e.g. the UI thread) and calling ShowDialog from thread B (e.g. a background Task or new thread), or caching a dialog instance and reusing it from another worker thread.","commonSituations":"Showing a file dialog from an async continuation that hopped to the thread pool; calling dialog.ShowDialog inside Task.Run; reusing a shared dialog field from a non-UI thread.","solutions":["Create and show the dialog on the same thread, ideally the UI thread","If on a background thread, marshal back to the dispatcher that owns the dialog: Application.Current.Dispatcher.Invoke(() => dlg.ShowDialog())","Create a fresh dialog instance on the thread where it will be shown instead of reusing a cached one","Avoid showing modal UI from worker threads entirely; collect input on the UI thread first"],"exampleFix":"// before\nvar dlg = new OpenFileDialog();\nTask.Run(() => dlg.ShowDialog());\n// after\nvar dlg = new OpenFileDialog();\nApplication.Current.Dispatcher.Invoke(() => dlg.ShowDialog());","handlingStrategy":"validation","validationCode":"if (dlg is CommonDialog && dlg.CheckAccess() == false) // conceptually: ensure same thread\n    Application.Current.Dispatcher.Invoke(() => dlg.ShowDialog());","typeGuard":"bool OnCorrectThread(CommonDialog d) => Thread.CurrentThread == d.GetType()\n    .GetField(\"_thread\", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(d);","tryCatchPattern":"try { dlg.ShowDialog(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"thread\"))\n{\n    Application.Current.Dispatcher.Invoke(() => dlg.ShowDialog());\n}","preventionTips":["Always create and show dialogs on the UI thread","Never call ShowDialog inside Task.Run or raw Thread.Start","Marshal to the owning Dispatcher when calling from background work"],"tags":["wpf","threading","dialog","ui-thread"],"backgroundTag":"thread-interrupted","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"}