@@ -549,6 +549,8 @@ void WindowEmperor::_dispatchSpecialKey(const MSG& msg) const
549
549
550
550
void WindowEmperor::_dispatchCommandline (winrt::TerminalApp::CommandlineArgs args)
551
551
{
552
+ _assertIsMainThread ();
553
+
552
554
const auto exitCode = args.ExitCode ();
553
555
554
556
if (const auto msg = args.ExitMessage (); !msg.empty ())
@@ -686,6 +688,8 @@ safe_void_coroutine WindowEmperor::_dispatchCommandlineCurrentDesktop(winrt::Ter
686
688
687
689
bool WindowEmperor::_summonWindow (const SummonWindowSelectionArgs& args) const
688
690
{
691
+ _assertIsMainThread ();
692
+
689
693
AppHost* window = nullptr ;
690
694
691
695
if (args.WindowID )
@@ -726,6 +730,8 @@ bool WindowEmperor::_summonWindow(const SummonWindowSelectionArgs& args) const
726
730
727
731
void WindowEmperor::_summonAllWindows () const
728
732
{
733
+ _assertIsMainThread ();
734
+
729
735
TerminalApp::SummonWindowBehavior args;
730
736
args.ToggleVisibility (false );
731
737
@@ -863,6 +869,9 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
863
869
// Did the window counter get out of sync? It shouldn't.
864
870
assert (_windowCount == gsl::narrow_cast<int32_t >(_windows.size ()));
865
871
872
+ // !!! NOTE !!!
873
+ // At least theoretically the lParam pointer may be invalid.
874
+ // We should only access it if we find it in our _windows array.
866
875
const auto host = reinterpret_cast <AppHost*>(lParam);
867
876
auto it = _windows.begin ();
868
877
const auto end = _windows.end ();
@@ -871,7 +880,15 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
871
880
{
872
881
if (host == it->get ())
873
882
{
874
- host->Close ();
883
+ // NOTE: The AppHost destructor is highly non-trivial.
884
+ //
885
+ // It _may_ call into XAML, which _may_ pump the message loop, which would then recursively
886
+ // re-enter this function, which _may_ then handle another WM_CLOSE_TERMINAL_WINDOW,
887
+ // which would change the _windows array, and invalidate our iterator and crash.
888
+ //
889
+ // We can prevent this by deferring destruction until after the erase() call.
890
+ const auto strong = *it;
891
+ strong->Close ();
875
892
_windows.erase (it);
876
893
break ;
877
894
}
0 commit comments