Repository: microsoft/terminal (language: cpp)

Issue:
Additional instances of WT crash on exit
### Windows Terminal version

1.18.1421.0

### Windows build number

10.0.19045.2728

### Other Software

N/A

### Steps to reproduce

This is probably related to
> All instances of Windows Terminal now run in the same process (https://github.com/microsoft/terminal/pull/14843)

1. Run WT.
2. Run WT again.


### Expected Behavior

Two WT windows

### Actual Behavior

Two WT windows and an extra error dialog:

![image](https://github.com/microsoft/terminal/assets/11453922/562626af-a480-4c5b-9e7f-d48ae718144f)

![image](https://github.com/microsoft/terminal/assets/11453922/f0ea0571-025c-4b7b-bbf4-0130f73ebf36)

Stack trace:
```
>	twinapi.appcore.dll!Microsoft::WRL::ActivationFactory<struct Microsoft::WRL::Implements<struct Microsoft::WRL::RuntimeClassFlags<3>,struct Windows::ApplicationModel::Core::ICoreApplication,struct Windows::ApplicationModel::Core::ICoreApplication2,struct Windows::ApplicationModel::Core::ICoreApplication3,struct Windows::ApplicationModel::Core::ICoreApplicationExit,struct Windows::ApplicationModel::Core::ICoreImmersiveApplication,struct Windows::ApplicationModel::Core::ICoreImmersiveApplication2,struct Windows::ApplicationModel::Core::ICoreImmersiveApplication3,struct Windows::ApplicationModel::Core::ICoreApplicationUnhandledError,struct Microsoft::WRL::Implements<struct Microsoft::WRL::RuntimeClassFlags<3>,struct Microsoft::WRL::CloakedIid<struct Windows::ApplicationModel::Core::ICoreApplicationUseCount>,struct Microsoft::WRL::CloakedIid<struct IServiceProvider>,struct Microsoft::WRL::CloakedIid<struct IObjectWithSite>,struct Microsoft::WRL::CloakedIid<struct Windows::ApplicationModel::Infrastructure::ICoreApplicationInitializat()	Unknown	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::ComPtr<Windows::Foundation::Collections::VectorChangedEventHandler<IInspectable *>>::InternalRelease() Line 346	C++	Symbols loaded.
 	[Inline Frame] Windows.UI.Xaml.dll!ctl::ComPtr<Windows::ApplicationModel::Core::ICoreApplication2>::{dtor}() Line 345	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!DirectUI::FrameworkApplication::HookBackgroundActivationEvents(bool fRegister=false) Line 1233	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!DirectUI::FrameworkApplication::~FrameworkApplication() Line 591	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::ComObject<DirectUI::FrameworkApplication>::`scalar deleting destructor'(unsigned int)	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::ComBase::ReleaseImpl() Line 307	C++	Symbols loaded.
 	[Inline Frame] TerminalApp.dll!winrt::Windows::Foundation::IUnknown::release_ref() Line 2161	C++	Symbols loaded.
 	[Inline Frame] TerminalApp.dll!winrt::Windows::Foundation::IUnknown::{dtor}() Line 2066	C++	Symbols loaded.
 	TerminalApp.dll!winrt::impl::root_implements<winrt::TerminalApp::implementation::PaletteItemTemplateSelector,winrt::TerminalApp::PaletteItemTemplateSelector,winrt::composing,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides2>::~root_implements<winrt::TerminalApp::implementation::PaletteItemTemplateSelector,winrt::TerminalApp::PaletteItemTemplateSelector,winrt::composing,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides2>() Line 7527	C++	Symbols loaded.
 	TerminalApp.dll!winrt::TerminalApp::implementation::App::`scalar deleting destructor'(unsigned int)	C++	Non-user code. Symbols loaded.
 	TerminalApp.dll!winrt::impl::produce_base<winrt::TerminalApp::implementation::App,winrt::TerminalApp::IApp,void>::Release() Line 7152	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::release_interface<DirectUI::FrameworkApplication>(DirectUI::FrameworkApplication * & pInterface=0x000002c37f81c600) Line 137	C++	Non-user code. Symbols loaded.
 	[Inline Frame] Windows.UI.Xaml.dll!DirectUI::FrameworkApplication::GlobalDeinit() Line 668	C++	Non-user code. Symbols loaded.
 	Windows.UI.Xaml.dll!DeinitializeDll() Line 319	C++	Non-user code. Symbols loaded.
 	Windows.UI.Xaml.dll!DllMain(HINSTANCE__ * hinstDLL, unsigned int fdwReason, void * __formal) Line 394	C++	Non-user code. Symbols loaded.
 	Windows.UI.Xaml.dll!dllmain_dispatch(HINSTANCE__ * const instance=0x00007ff919460000, const unsigned long reason=0, void * const reserved=0x0000000000000001) Line 200	C++	Non-user code. Symbols loaded.
 	ntdll.dll!LdrpCallInitRoutine()	Unknown	Non-user code. Symbols loaded without source information.
 	ntdll.dll!LdrShutdownProcess()	Unknown	Non-user code. Symbols loaded without source information.
 	ntdll.dll!RtlExitUserProcess()	Unknown	Non-user code. Symbols loaded without source information.
 	kernel32.dll!ExitProcessImplementation()	Unknown	Non-user code. Symbols loaded without source information.
 	ucrtbase.dll!exit_or_terminate_process()	Unknown	Non-user code. Symbols loaded without source information.
 	ucrtbase.dll!common_exit()	Unknown	Non-user code. Symbols loaded without source information.
 	WindowsTerminal.exe!__scrt_common_main_seh() Line 295	C++	Non-user code. Symbols loaded.
 	kernel32.dll!BaseThreadInitThunk()	Unknown	Non-user code. Symbols loaded without source information.
 	ntdll.dll!RtlUserThreadStart()	Unknown	Non-user code. Symbols loaded without source information.

```

After closing the error dialog everything works normally.

Additional instances of WT crash on exit
### Windows Terminal version

1.18.1421.0

### Windows build number

10.0.19045.2728

### Other Software

N/A

### Steps to reproduce

This is probably related to
> All instances of Windows Terminal now run in the same process (https://github.com/microsoft/terminal/pull/14843)

1. Run WT.
2. Run WT again.


### Expected Behavior

Two WT windows

### Actual Behavior

Two WT windows and an extra error dialog:

![image](https://github.com/microsoft/terminal/assets/11453922/562626af-a480-4c5b-9e7f-d48ae718144f)

![image](https://github.com/microsoft/terminal/assets/11453922/f0ea0571-025c-4b7b-bbf4-0130f73ebf36)

Stack trace:
```
>	twinapi.appcore.dll!Microsoft::WRL::ActivationFactory<struct Microsoft::WRL::Implements<struct Microsoft::WRL::RuntimeClassFlags<3>,struct Windows::ApplicationModel::Core::ICoreApplication,struct Windows::ApplicationModel::Core::ICoreApplication2,struct Windows::ApplicationModel::Core::ICoreApplication3,struct Windows::ApplicationModel::Core::ICoreApplicationExit,struct Windows::ApplicationModel::Core::ICoreImmersiveApplication,struct Windows::ApplicationModel::Core::ICoreImmersiveApplication2,struct Windows::ApplicationModel::Core::ICoreImmersiveApplication3,struct Windows::ApplicationModel::Core::ICoreApplicationUnhandledError,struct Microsoft::WRL::Implements<struct Microsoft::WRL::RuntimeClassFlags<3>,struct Microsoft::WRL::CloakedIid<struct Windows::ApplicationModel::Core::ICoreApplicationUseCount>,struct Microsoft::WRL::CloakedIid<struct IServiceProvider>,struct Microsoft::WRL::CloakedIid<struct IObjectWithSite>,struct Microsoft::WRL::CloakedIid<struct Windows::ApplicationModel::Infrastructure::ICoreApplicationInitializat()	Unknown	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::ComPtr<Windows::Foundation::Collections::VectorChangedEventHandler<IInspectable *>>::InternalRelease() Line 346	C++	Symbols loaded.
 	[Inline Frame] Windows.UI.Xaml.dll!ctl::ComPtr<Windows::ApplicationModel::Core::ICoreApplication2>::{dtor}() Line 345	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!DirectUI::FrameworkApplication::HookBackgroundActivationEvents(bool fRegister=false) Line 1233	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!DirectUI::FrameworkApplication::~FrameworkApplication() Line 591	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::ComObject<DirectUI::FrameworkApplication>::`scalar deleting destructor'(unsigned int)	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::ComBase::ReleaseImpl() Line 307	C++	Symbols loaded.
 	[Inline Frame] TerminalApp.dll!winrt::Windows::Foundation::IUnknown::release_ref() Line 2161	C++	Symbols loaded.
 	[Inline Frame] TerminalApp.dll!winrt::Windows::Foundation::IUnknown::{dtor}() Line 2066	C++	Symbols loaded.
 	TerminalApp.dll!winrt::impl::root_implements<winrt::TerminalApp::implementation::PaletteItemTemplateSelector,winrt::TerminalApp::PaletteItemTemplateSelector,winrt::composing,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides2>::~root_implements<winrt::TerminalApp::implementation::PaletteItemTemplateSelector,winrt::TerminalApp::PaletteItemTemplateSelector,winrt::composing,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides,winrt::Windows::UI::Xaml::Controls::IDataTemplateSelectorOverrides2>() Line 7527	C++	Symbols loaded.
 	TerminalApp.dll!winrt::TerminalApp::implementation::App::`scalar deleting destructor'(unsigned int)	C++	Non-user code. Symbols loaded.
 	TerminalApp.dll!winrt::impl::produce_base<winrt::TerminalApp::implementation::App,winrt::TerminalApp::IApp,void>::Release() Line 7152	C++	Symbols loaded.
 	Windows.UI.Xaml.dll!ctl::release_interface<DirectUI::FrameworkApplication>(DirectUI::FrameworkApplication * & pInterface=0x000002c37f81c600) Line 137	C++	Non-user code. Symbols loaded.
 	[Inline Frame] Windows.UI.Xaml.dll!DirectUI::FrameworkApplication::GlobalDeinit() Line 668	C++	Non-user code. Symbols loaded.
 	Windows.UI.Xaml.dll!DeinitializeDll() Line 319	C++	Non-user code. Symbols loaded.
 	Windows.UI.Xaml.dll!DllMain(HINSTANCE__ * hinstDLL, unsigned int fdwReason, void * __formal) Line 394	C++	Non-user code. Symbols loaded.
 	Windows.UI.Xaml.dll!dllmain_dispatch(HINSTANCE__ * const instance=0x00007ff919460000, const unsigned long reason=0, void * const reserved=0x0000000000000001) Line 200	C++	Non-user code. Symbols loaded.
 	ntdll.dll!LdrpCallInitRoutine()	Unknown	Non-user code. Symbols loaded without source information.
 	ntdll.dll!LdrShutdownProcess()	Unknown	Non-user code. Symbols loaded without source information.
 	ntdll.dll!RtlExitUserProcess()	Unknown	Non-user code. Symbols loaded without source information.
 	kernel32.dll!ExitProcessImplementation()	Unknown	Non-user code. Symbols loaded without source information.
 	ucrtbase.dll!exit_or_terminate_process()	Unknown	Non-user code. Symbols loaded without source information.
 	ucrtbase.dll!common_exit()	Unknown	Non-user code. Symbols loaded without source information.
 	WindowsTerminal.exe!__scrt_common_main_seh() Line 295	C++	Non-user code. Symbols loaded.
 	kernel32.dll!BaseThreadInitThunk()	Unknown	Non-user code. Symbols loaded without source information.
 	ntdll.dll!RtlUserThreadStart()	Unknown	Non-user code. Symbols loaded without source information.

```

After closing the error dialog everything works normally.



Discussion / hints:
Hmmmmmm. When this happens, are there two windowsterminal.exe processes running in Task Manager? Any ideas which the error is coming from? 
I wonder if we need to pump the message loop on the main thread similarly to how we do it for each window thread. This does seem to be an after effect of us calling `detach_abi` on the `_app` though... 🤔
> are there two windowsterminal.exe processes running in Task Manager?

Three actually.

After the first run:

![image](https://github.com/microsoft/terminal/assets/11453922/c297d2bd-a0df-45ae-9454-4626e002ed1a)

After the second run:

![image](https://github.com/microsoft/terminal/assets/11453922/001f5d71-0716-4c2c-8ad9-187ab0800a38)

> Any ideas which the error is coming from?

The second parent (PID 7528 on the screenshot). At least it is the one VS attaches to.

P.S. I think Windows doesn't show the "app has stopped working" dialog by default these days, maybe this is why it got overlooked. The error should still be in the event log under "administrative events" and the the dialog can be re-enabled in [group policy](https://superuser.com/questions/1246626/is-it-by-design-that-windows-10-no-longer-displays-app-has-stopped-working-d/1349113#1349113).
Huh. So the `wt` that handed off to the main instance, crashed when it died (of natural causes). And it crashed... dtoring our `App`? And what the heck is that `TerminalApp.dll!winrt::impl::root_implements<winrt::TerminalApp::implementation::PaletteItemTemplateSelector` frame doing there?

_Maybe_ this regressed in #15397. But I almost don't think that's right - we shouldn't have even made a window in that process which we could leak.

> I think Windows doesn't show the "app has stopped working" dialog by default these days, maybe this is why it got overlooked

FWIW I pretty much always run with "post-mortem debugging" enabled for WinDbg. So usually we catch things like this.
Hmm. I can repro this in a VM - even on the build with the leak taken out. So it's not that.

<details>
<summary>er, no, this was useless</summary>

There's a stashed exception in there:

  | Name | Value | Type
-- | -- | -- | --
◢ | $exceptionstack | [9 Frames, Microsoft.Terminal.Remoting.dll!winrt::impl::consume_Microsoft_Terminal_Remoting_IMonarch<winrt::Microsoft::Terminal::Remoting::IMonarch>::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args) Line 122] |  
  | [0] | [External Code] | void*
  | [1] | Microsoft.Terminal.Remoting.dll!winrt::impl::consume_Microsoft_Terminal_Remoting_IMonarch<winrt::Microsoft::Terminal::Remoting::IMonarch>::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args) Line 122 | void*
  | [2] | Microsoft.Terminal.Remoting.dll!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::_proposeToMonarch(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args) Line 272 | void*
  | [3] | Microsoft.Terminal.Remoting.dll!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args, const bool isolatedMode) Line 135 | void*
  | [4] | Microsoft.Terminal.Remoting.dll!winrt::impl::produce<winrt::Microsoft::Terminal::Remoting::implementation::WindowManager,winrt::Microsoft::Terminal::Remoting::IWindowManager>::ProposeCommandline(void * args, bool isolatedMode, void * * result) Line 1947 | void*
  | [5] | WindowsTerminal.exe!winrt::impl::consume_Microsoft_Terminal_Remoting_IWindowManager<winrt::Microsoft::Terminal::Remoting::IWindowManager>::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args, bool isolatedMode) Line 752 | void*
  | [6] | WindowsTerminal.exe!WindowEmperor::HandleCommandlineArgs() Line 117 | void*
  | [7] | WindowsTerminal.exe!wWinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, wchar_t * __formal, int __formal) Line 118 | void*
  | [8] | [External Code] | void*


</details>



I hate it so much

```diff
diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
index a268dfd59..1bb8b2711 100644
--- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp
+++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
@@ -41,10 +41,30 @@ WindowEmperor::WindowEmperor() noexcept :

 WindowEmperor::~WindowEmperor()
 {
+    if (_app)^M
     _app.Close();
     _app = nullptr;
 }

+static bool IsWindows11()^M
+{^M
+    static const bool isWindows11 = []() {^M
+        OSVERSIONINFOEXW osver{};^M
+        osver.dwOSVersionInfoSize = sizeof(osver);^M
+        osver.dwBuildNumber = 22000;^M
+^M
+        DWORDLONG dwlConditionMask = 0;^M
+        VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);^M
+^M
+        if (VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE)^M
+        {^M
+            return true;^M
+        }^M
+        return false;^M
+    }();^M
+    return isWindows11;^M
+}^M
+^M
 void _buildArgsFromCommandline(std::vector<winrt::hstring>& args)
 {
     if (auto commandline{ GetCommandLineW() })
@@ -97,7 +117,8 @@ bool WindowEmperor::HandleCommandlineArgs()

     const auto result = _manager.ProposeCommandline(eventArgs, isolatedMode);

-    if (result.ShouldCreateWindow())
+    const bool makeWindow = result.ShouldCreateWindow();^M
+    if (makeWindow)^M
     {
         _createNewWindowThread(Remoting::WindowRequestedArgs{ result, eventArgs });

@@ -111,9 +132,15 @@ bool WindowEmperor::HandleCommandlineArgs()
             AppHost::s_DisplayMessageBox(res);
             ExitThread(res.ExitCode);
         }
+^M
+        if (!IsWindows11())^M
+        {^M
+            auto a{ _app };^M
+            winrt::detach_abi(_app);^M
+        }^M
     }

-    return result.ShouldCreateWindow();
+    return makeWindow;^M
 }
```
That horrible diff will "leak" the `App` on Windows 10. "Leak" in quotes, because the whole process is exiting, so the entire thing is just gonna get released instantly after that when the process is exited. 

And you wanna know what? We _used to do that intentionally_. See #5629.

We actually still do leak it intentionally. Problem is, we only leak it for the "monarch" process, the main one, with the windows. The other peasant process that just immediately fucks off - that one doesn't leak and GUESS WHAT. That crashes. Cause of course it does.
Hmmmmmm. When this happens, are there two windowsterminal.exe processes running in Task Manager? Any ideas which the error is coming from? 
I wonder if we need to pump the message loop on the main thread similarly to how we do it for each window thread. This does seem to be an after effect of us calling `detach_abi` on the `_app` though... 🤔
> are there two windowsterminal.exe processes running in Task Manager?

Three actually.

After the first run:

![image](https://github.com/microsoft/terminal/assets/11453922/c297d2bd-a0df-45ae-9454-4626e002ed1a)

After the second run:

![image](https://github.com/microsoft/terminal/assets/11453922/001f5d71-0716-4c2c-8ad9-187ab0800a38)

> Any ideas which the error is coming from?

The second parent (PID 7528 on the screenshot). At least it is the one VS attaches to.

P.S. I think Windows doesn't show the "app has stopped working" dialog by default these days, maybe this is why it got overlooked. The error should still be in the event log under "administrative events" and the the dialog can be re-enabled in [group policy](https://superuser.com/questions/1246626/is-it-by-design-that-windows-10-no-longer-displays-app-has-stopped-working-d/1349113#1349113).
Huh. So the `wt` that handed off to the main instance, crashed when it died (of natural causes). And it crashed... dtoring our `App`? And what the heck is that `TerminalApp.dll!winrt::impl::root_implements<winrt::TerminalApp::implementation::PaletteItemTemplateSelector` frame doing there?

_Maybe_ this regressed in #15397. But I almost don't think that's right - we shouldn't have even made a window in that process which we could leak.

> I think Windows doesn't show the "app has stopped working" dialog by default these days, maybe this is why it got overlooked

FWIW I pretty much always run with "post-mortem debugging" enabled for WinDbg. So usually we catch things like this.
Hmm. I can repro this in a VM - even on the build with the leak taken out. So it's not that.

<details>
<summary>er, no, this was useless</summary>

There's a stashed exception in there:

  | Name | Value | Type
-- | -- | -- | --
◢ | $exceptionstack | [9 Frames, Microsoft.Terminal.Remoting.dll!winrt::impl::consume_Microsoft_Terminal_Remoting_IMonarch<winrt::Microsoft::Terminal::Remoting::IMonarch>::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args) Line 122] |  
  | [0] | [External Code] | void*
  | [1] | Microsoft.Terminal.Remoting.dll!winrt::impl::consume_Microsoft_Terminal_Remoting_IMonarch<winrt::Microsoft::Terminal::Remoting::IMonarch>::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args) Line 122 | void*
  | [2] | Microsoft.Terminal.Remoting.dll!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::_proposeToMonarch(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args) Line 272 | void*
  | [3] | Microsoft.Terminal.Remoting.dll!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args, const bool isolatedMode) Line 135 | void*
  | [4] | Microsoft.Terminal.Remoting.dll!winrt::impl::produce<winrt::Microsoft::Terminal::Remoting::implementation::WindowManager,winrt::Microsoft::Terminal::Remoting::IWindowManager>::ProposeCommandline(void * args, bool isolatedMode, void * * result) Line 1947 | void*
  | [5] | WindowsTerminal.exe!winrt::impl::consume_Microsoft_Terminal_Remoting_IWindowManager<winrt::Microsoft::Terminal::Remoting::IWindowManager>::ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs & args, bool isolatedMode) Line 752 | void*
  | [6] | WindowsTerminal.exe!WindowEmperor::HandleCommandlineArgs() Line 117 | void*
  | [7] | WindowsTerminal.exe!wWinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, wchar_t * __formal, int __formal) Line 118 | void*
  | [8] | [External Code] | void*


</details>



I hate it so much

```diff
diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
index a268dfd59..1bb8b2711 100644
--- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp
+++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
@@ -41,10 +41,30 @@ WindowEmperor::WindowEmperor() noexcept :

 WindowEmperor::~WindowEmperor()
 {
+    if (_app)^M
     _app.Close();
     _app = nullptr;
 }

+static bool IsWindows11()^M
+{^M
+    static const bool isWindows11 = []() {^M
+        OSVERSIONINFOEXW osver{};^M
+        osver.dwOSVersionInfoSize = sizeof(osver);^M
+        osver.dwBuildNumber = 22000;^M
+^M
+        DWORDLONG dwlConditionMask = 0;^M
+        VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);^M
+^M
+        if (VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE)^M
+        {^M
+            return true;^M
+        }^M
+        return false;^M
+    }();^M
+    return isWindows11;^M
+}^M
+^M
 void _buildArgsFromCommandline(std::vector<winrt::hstring>& args)
 {
     if (auto commandline{ GetCommandLineW() })
@@ -97,7 +117,8 @@ bool WindowEmperor::HandleCommandlineArgs()

     const auto result = _manager.ProposeCommandline(eventArgs, isolatedMode);

-    if (result.ShouldCreateWindow())
+    const bool makeWindow = result.ShouldCreateWindow();^M
+    if (makeWindow)^M
     {
         _createNewWindowThread(Remoting::WindowRequestedArgs{ result, eventArgs });

@@ -111,9 +132,15 @@ bool WindowEmperor::HandleCommandlineArgs()
             AppHost::s_DisplayMessageBox(res);
             ExitThread(res.ExitCode);
         }
+^M
+        if (!IsWindows11())^M
+        {^M
+            auto a{ _app };^M
+            winrt::detach_abi(_app);^M
+        }^M
     }

-    return result.ShouldCreateWindow();
+    return makeWindow;^M
 }
```
That horrible diff will "leak" the `App` on Windows 10. "Leak" in quotes, because the whole process is exiting, so the entire thing is just gonna get released instantly after that when the process is exited. 

And you wanna know what? We _used to do that intentionally_. See #5629.

We actually still do leak it intentionally. Problem is, we only leak it for the "monarch" process, the main one, with the windows. The other peasant process that just immediately fucks off - that one doesn't leak and GUESS WHAT. That crashes. Cause of course it does.

Fix patch:
diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
index 77701a354ce..54d5e2d4f4a 100644
--- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp
+++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
@@ -37,6 +37,20 @@ WindowEmperor::WindowEmperor() noexcept :
     });
 
     _dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
+
+    // BODGY
+    //
+    // There's a mysterious crash in XAML on Windows 10 if you just let the App
+    // get dtor'd. By all accounts, it doesn't make sense. To mitigate this, we
+    // need to intentionally leak a reference to our App. Crazily, if you just
+    // let the app get cleaned up with the rest of the process when the process
+    // exits, then it doesn't crash. But if you let it get explicitly dtor'd, it
+    // absolutely will crash on exit.
+    //
+    // GH#15410 has more details.
+
+    auto a{ _app };
+    ::winrt::detach_abi(a);
 }
 
 WindowEmperor::~WindowEmperor()
@@ -296,24 +310,6 @@ void WindowEmperor::_becomeMonarch()
     // We want at least some delay to prevent the first save from overwriting
     _getWindowLayoutThrottler.emplace(std::move(std::chrono::seconds(10)), std::move([this]() { _saveWindowLayoutsRepeat(); }));
     _getWindowLayoutThrottler.value()();
-
-    // BODGY
-    //
-    // We've got a weird crash that happens terribly inconsistently, but pretty
-    // readily on migrie's laptop, only in Debug mode. Apparently, there's some
-    // weird ref-counting magic that goes on during teardown, and our
-    // Application doesn't get closed quite right, which can cause us to crash
-    // into the debugger. This of course, only happens on exit, and happens
-    // somewhere in the XamlHost.dll code.
-    //
-    // Crazily, if we _manually leak the Application_ here, then the crash
-    // doesn't happen. This doesn't matter, because we really want the
-    // Application to live for _the entire lifetime of the process_, so the only
-    // time when this object would actually need to get cleaned up is _during
-    // exit_. So we can safely leak this Application object, and have it just
-    // get cleaned up normally when our process exits.
-    auto a{ _app };
-    ::winrt::detach_abi(a);
 }
 
 // sender and args are always nullptr


Test patch: