Repository: microsoft/terminal (language: cpp)

Issue:
Some internal crash reports
Just filing notes here for posterity. Issue will be updated as I investigate. 

## MSFT:35731327 - Closed no repro, but definitely still reproing.

<details>
<summary>Stack</summary>

```
0:000> k
 # Child-SP          RetAddr               Call Site
00 00000039`af0fb268 00007ffd`96847aa9     ntdll!ZwWaitForMultipleObjects+0x14 [minkernel\ntdll\daytona\objfre\amd64\usrstubs.asm @ 947] 
01 00000039`af0fb270 00007ffd`968479ae     KERNELBASE!WaitForMultipleObjectsEx+0xe9 [minkernel\kernelbase\synch.c @ 1551] 
02 00000039`af0fb550 00007ffd`973d27af     KERNELBASE!WaitForMultipleObjects+0xe [minkernel\kernelbase\synch.c @ 1403] 
03 00000039`af0fb590 00007ffd`973d21ee     kernel32!WerpReportFaultInternal+0x587 [onecore\windows\feedback\core\faultrep\lib\faultrep.cpp @ 987] 
04 00000039`af0fb6b0 00007ffd`9694541b     kernel32!WerpReportFault+0xbe [onecore\windows\feedback\core\faultrep\lib\faultrep.cpp @ 1298] 
05 00000039`af0fb6f0 00007ffd`9917bec5     KERNELBASE!UnhandledExceptionFilter+0x3db [minkernel\kernelbase\xcpt.c @ 685] 
06 (Inline Function) --------`--------     ntdll!RtlpThreadExceptionFilter+0xa3 [minkernel\ntdll\rtlstrt.c @ 960] 
07 00000039`af0fb810 00007ffd`99163177     ntdll!RtlUserThreadStart$filt$0+0xb4 [minkernel\ntdll\rtlstrt.c @ 1167] 
08 00000039`af0fb850 00007ffd`99178a0f     ntdll!__C_specific_handler+0x97 [minkernel\crts\crtw32\misc\riscchandler.c @ 433] 
09 00000039`af0fb8c0 00007ffd`990e3de6     ntdll!RtlpExecuteHandlerForException+0xf [minkernel\ntos\rtl\amd64\xcptmisc.asm @ 132] 
0a 00000039`af0fb8f0 00007ffd`991779fe     ntdll!RtlDispatchException+0x286 [minkernel\ntos\rtl\amd64\exdsptch.c @ 655] 
0b 00000039`af0fc040 00007ffd`83c41a10     ntdll!KiUserExceptionDispatch+0x2e [minkernel\ntos\rtl\amd64\trampoln.asm @ 755] 
0c (Inline Function) --------`--------     Microsoft_Terminal_Remoting!winrt::impl::consume_Microsoft_Terminal_Remoting_IWindowActivatedArgs<winrt::Microsoft::Terminal::Remoting::IWindowActivatedArgs>::PeasantID+0xb [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\Microsoft.Terminal.Remoting.h @ 616] 
0d (Inline Function) --------`--------     Microsoft_Terminal_Remoting!winrt::Microsoft::Terminal::Remoting::implementation::WindowActivatedArgs::{ctor}+0x2a [C:\a\_work\1\s\src\cascadia\Remoting\WindowActivatedArgs.h @ 51] 
0e (Inline Function) --------`--------     Microsoft_Terminal_Remoting!winrt::make_self+0x46 [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\base.h @ 7787] 
0f 00000039`af0fc7e0 00007ffd`83c5d49f     Microsoft_Terminal_Remoting!winrt::Microsoft::Terminal::Remoting::implementation::Monarch::HandleActivatePeasant+0x80 [C:\a\_work\1\s\src\cascadia\Remoting\Monarch.cpp @ 362] 
10 00000039`af0fc990 00007ffd`83c4d567     Microsoft_Terminal_Remoting!winrt::impl::produce<winrt::Microsoft::Terminal::Remoting::implementation::Monarch,winrt::Microsoft::Terminal::Remoting::IMonarch>::HandleActivatePeasant+0x2f [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\Microsoft.Terminal.Remoting.h @ 985] 
11 (Inline Function) --------`--------     Microsoft_Terminal_Remoting!winrt::impl::consume_Microsoft_Terminal_Remoting_IMonarch<winrt::Microsoft::Terminal::Remoting::IMonarch>::HandleActivatePeasant+0x13 [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\Microsoft.Terminal.Remoting.h @ 109] 
12 00000039`af0fc9d0 00007ffd`83c4b4b9     Microsoft_Terminal_Remoting!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::_createMonarchAndCallbacks+0xa747 [C:\a\_work\1\s\src\cascadia\Remoting\WindowManager.cpp @ 256] 
13 00000039`af0fcb50 00007ffd`914f1080     Microsoft_Terminal_Remoting!`winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::_createOurPeasant'::`1'::catch$174+0x19 [C:\a\_work\1\s\src\cascadia\Remoting\WindowManager.cpp @ 313] 
14 00000039`af0fcb90 00007ffd`914f26a5     VCRUNTIME140_1!_CallSettingFrame_LookupContinuationIndex+0x20 [d:\a01\_work\12\s\src\vctools\crt\vcruntime\src\eh\amd64\handlers.asm @ 98] 
15 00000039`af0fcbc0 00007ffd`99178256     VCRUNTIME140_1!__FrameHandler4::CxxCallCatchBlock+0x115 [d:\a01\_work\12\s\src\vctools\crt\vcruntime\src\eh\frame.cpp @ 1393] 
16 00000039`af0fcca0 00007ffd`83c4d397     ntdll!RcFrameConsolidation+0x6 [minkernel\ntos\rtl\amd64\capture.asm @ 1147] 
17 (Inline Function) --------`--------     Microsoft_Terminal_Remoting!winrt::check_hresult+0xa846 [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\base.h @ 5016] 
18 (Inline Function) --------`--------     Microsoft_Terminal_Remoting!winrt::impl::consume_Microsoft_Terminal_Remoting_IMonarch<winrt::Microsoft::Terminal::Remoting::IMonarch>::AddPeasant+0xa86d [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\Microsoft.Terminal.Remoting.h @ 92] 
19 00000039`af0fef60 00007ffd`83c42553     Microsoft_Terminal_Remoting!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::_createOurPeasant+0xaaa7 [C:\a\_work\1\s\src\cascadia\Remoting\WindowManager.cpp @ 305] 
1a 00000039`af0ff0b0 00007ffd`83c4113f     Microsoft_Terminal_Remoting!winrt::Microsoft::Terminal::Remoting::implementation::WindowManager::ProposeCommandline+0x1d3 [C:\a\_work\1\s\src\cascadia\Remoting\WindowManager.cpp @ 190] 
1b 00000039`af0ff1b0 00007ff7`9b592cee     Microsoft_Terminal_Remoting!winrt::impl::produce<winrt::Microsoft::Terminal::Remoting::implementation::WindowManager,winrt::Microsoft::Terminal::Remoting::IWindowManager>::ProposeCommandline+0x2f [C:\a\_work\1\s\src\cascadia\Remoting\Generated Files\winrt\Microsoft.Terminal.Remoting.h @ 1703] 
1c (Inline Function) --------`--------     WindowsTerminal!winrt::impl::consume_Microsoft_Terminal_Remoting_IWindowManager<winrt::Microsoft::Terminal::Remoting::IWindowManager>::ProposeCommandline+0x19 [C:\a\_work\1\s\src\cascadia\WindowsTerminal\Generated Files\winrt\Microsoft.Terminal.Remoting.h @ 651] 
1d 00000039`af0ff1f0 00007ff7`9b594c4c     WindowsTerminal!AppHost::_HandleCommandlineArgs+0x1de [C:\a\_work\1\s\src\cascadia\WindowsTerminal\AppHost.cpp @ 184] 
1e 00000039`af0ff4d0 00007ff7`9b591280     WindowsTerminal!AppHost::AppHost+0x1dc [C:\a\_work\1\s\src\cascadia\WindowsTerminal\AppHost.cpp @ 50] 
1f 00000039`af0ff7d0 00007ff7`9b59ca72     WindowsTerminal!wWinMain+0x110
```

</details>

> Pulled two dumps there -
> * they're defterm invokes (-Embeddding)
> * they are the king (different from the other bug)
> 
* the code that hits there is a null LastActivatedArgs, akin to [not an actual fix for 12169, but a crash nonetheless · microsoft/terminal@dd213a5 (github.com)](https://github.com/microsoft/terminal/commit/dd213a5c180997e8b761ca9f8078c0ba58503a0b) but in a different spot
> 

> ah that one's tricky, there aren't tests at exactly that level. The defterm is getting created just as the king window is closing. So during proposeCommandline it decides it needs to also instantiate a new Monarch itself, and then tell the Monarch about itself (including when we were laste activated). however, we're still in the process of setting up the window. The window hasn't been activated yet, so the Peasant doesn't have a lastactivatedargs.
> 
> I woulda thought this try/catch would have got it though:
> 
> ```
>         try
>         {
>             localArgs = winrt::make_self<implementation::WindowActivatedArgs>(args);
>             // This method will actually do the hard work
>             _doHandleActivatePeasant(localArgs);
>         }
>         catch (...)
>         {
>             TraceLoggingWrite(g_hRemotingProvider,
>                               "Monarch_HandleActivatePeasant_Failed",
>                               TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
>                               TraceLoggingKeyword(TIL_KEYWORD_TRACE));
>         }
> ```

**SOLUTION**: Should be easy enough to add a `null` check to `Monarch::HandleActivatePeasant` (and anywhere else there's a `WindowActivatedArgs` really)

## 🔥 MSFT:32518679 (ARM version), MSFT:32279047 (AMD64 version)

Happening as early as module versions `1.11.[2108, 2109, 2110]`, and all the way till `1.13.2202.8005`


> Hmm. the _windowManager isn't the king. the _monarch isn't null, so it was created, and in another process. We're not a peasant yet so it makes sense there's no election thread or _peasant yet. 
> 
> given that _shouldCreateWindow is false, either:
> * we crashed in const auto result = _monarch.ProposeCommandline(args);
> * we made it past that, and crashed... where? When we call out to the monarch process? I'd imagine that would have given us a RPC error of some sort if that itself failed, so maybe the Monarch process had the stack overflow? but in that case I'd imagine we'd be getting hits for FindTargetWindow in an actual monarch process.
> 
> We may be able to repro this by launching the Terminal then launching cmd.exe, to force defterm to engage....

A thought: `_monarch.ProposeCommandline` could fail. That's a potentially cross-proc hop there, and it's not try/caught. So in that scenario:
* the user opened a window[A] that became the monarch
* they ran cmd.exe which started a defterm handoff
* that gets into `WindowManager::ProposeCommandline`, which starts to ask the monarch via `ProposeCommandline`
* On that line, the monarch dies. That would raise an exception - would that be the `c0000409`/`STATUS_STACK_BUFFER_OVERRUN` we're seeing? because that seems... unlikely. 

There's piles of tracing around here. We should be able to get traces from these crashes, right? _right_?

After more investigating:

```c++
            // TODO! If the monarch dies or otherwise fails, what do we do here?
            //
            // I suppose we could emulate this by sticking a breakpoint in
            // TerminalApp!winrt::TerminalApp::implementation::AppLogic::_doFindTargetWindow,
            // starting a terminal, starting a defterm, and when that BP gets
            // hit, kill the original one and see what happens here.
            const auto result = _monarch.ProposeCommandline(args);
            // Damn, killing the monarch exactly here still gets us -2147023170,
            // RPC_S_CALL_FAILED, which is exactly what you'd expect

```

So it's not that the monarch died. Something caused a buffer overrun and I have no idea what because the stack is just no longer useful, and [try/catching that won't work either](https://stackoverflow.com/questions/33900453/is-there-a-way-to-catch-a-status-stack-buffer-overrun-error-programmatically). We'll need to come up with something next week.


Discussion / hints:

Fix patch:
diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt
index 13d32233b58..daf1feb13af 100644
--- a/.github/actions/spelling/allow/apis.txt
+++ b/.github/actions/spelling/allow/apis.txt
@@ -72,6 +72,7 @@ IFACEMETHOD
 IFile
 IInheritable
 IMap
+IMonarch
 IObject
 iosfwd
 IPackage
diff --git a/src/cascadia/Remoting/Monarch.cpp b/src/cascadia/Remoting/Monarch.cpp
index eed247ab41a..ba1f76a1a5f 100644
--- a/src/cascadia/Remoting/Monarch.cpp
+++ b/src/cascadia/Remoting/Monarch.cpp
@@ -353,6 +353,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
     // - <none>
     void Monarch::HandleActivatePeasant(const Remoting::WindowActivatedArgs& args)
     {
+        if (args == nullptr)
+        {
+            // MSFT:35731327, GH #12624. There's a chance that the way the
+            // window gets set up for defterm, the ActivatedArgs haven't been
+            // created for this window yet. Check here and just ignore them if
+            // they're null. They'll come back with real args soon
+            return;
+        }
         // Start by making a local copy of these args. It's easier for us if our
         // tracking of these args is all in-proc. That way, the only thing that
         // could fail due to the peasant dying is _this first copy_.
@@ -418,6 +426,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
     // - <none>
     void Monarch::_doHandleActivatePeasant(const winrt::com_ptr<implementation::WindowActivatedArgs>& localArgs)
     {
+        // We're sure that localArgs isn't null here, we checked before in our
+        // one caller (in Monarch::HandleActivatePeasant)
+
         const auto newLastActiveTime = localArgs->ActivatedTime().time_since_epoch().count();
 
         // * Check all the current lists to look for this peasant.
diff --git a/src/cascadia/Remoting/Monarch.idl b/src/cascadia/Remoting/Monarch.idl
index f60b3997a64..08c7b63cbda 100644
--- a/src/cascadia/Remoting/Monarch.idl
+++ b/src/cascadia/Remoting/Monarch.idl
@@ -44,8 +44,8 @@ namespace Microsoft.Terminal.Remoting
         String TabTitle;
     };
 
-    [default_interface] runtimeclass Monarch {
-        Monarch();
+    interface IMonarch
+    {
 
         UInt64 GetPID();
         UInt64 AddPeasant(IPeasant peasant);
@@ -67,4 +67,9 @@ namespace Microsoft.Terminal.Remoting
         event Windows.Foundation.TypedEventHandler<Object, Object> WindowClosed;
         event Windows.Foundation.TypedEventHandler<Object, QuitAllRequestedArgs> QuitAllRequested;
     };
+
+    [default_interface] runtimeclass Monarch : IMonarch
+    {
+        Monarch();
+    };
 }
diff --git a/src/cascadia/Remoting/WindowManager.cpp b/src/cascadia/Remoting/WindowManager.cpp
index 8ce04464cda..89f337830bf 100644
--- a/src/cascadia/Remoting/WindowManager.cpp
+++ b/src/cascadia/Remoting/WindowManager.cpp
@@ -77,57 +77,161 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
         }
     }
 
-    void WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args)
+    void WindowManager::_proposeToMonarch(const Remoting::CommandlineArgs& args,
+                                          std::optional<uint64_t>& givenID,
+                                          winrt::hstring& givenName)
     {
-        // If we're the king, we _definitely_ want to process the arguments, we were
-        // launched with them!
-        //
-        // Otherwise, the King will tell us if we should make a new window
-        _shouldCreateWindow = _isKing;
-        std::optional<uint64_t> givenID;
-        winrt::hstring givenName{};
-        if (!_isKing)
+        // these two errors are Win32 errors, convert them to HRESULTS so we can actually compare below.
+        static constexpr HRESULT RPC_SERVER_UNAVAILABLE_HR = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
+        static constexpr HRESULT RPC_CALL_FAILED_HR = HRESULT_FROM_WIN32(RPC_S_CALL_FAILED);
+
+        // The monarch may respond back "you should be a new
+        // window, with ID,name of (id, name)". Really the responses are:
+        // * You should not create a new window
+        // * Create a new window (but without a given ID or name). The
+        //   Monarch will assign your ID/name later
+        // * Create a new window, and you'll have this ID or name
+        //   - This is the case where the user provides `wt -w 1`, and
+        //     there's no existing window 1
+
+        // You can emulate the monarch dying by: starting a terminal, sticking a
+        // breakpoint in
+        // TerminalApp!winrt::TerminalApp::implementation::AppLogic::_doFindTargetWindow,
+        // starting a defterm, and when that BP gets hit, kill the original
+        // monarch, and see what happens here.
+
+        bool proposedCommandline = false;
+        Remoting::ProposeCommandlineResult result{ nullptr };
+        while (!proposedCommandline)
         {
-            // The monarch may respond back "you should be a new
-            // window, with ID,name of (id, name)". Really the responses are:
-            // * You should not create a new window
-            // * Create a new window (but without a given ID or name). The
-            //   Monarch will assign your ID/name later
-            // * Create a new window, and you'll have this ID or name
-            //   - This is the case where the user provides `wt -w 1`, and
-            //     there's no existing window 1
-
-            const auto result = _monarch.ProposeCommandline(args);
-            _shouldCreateWindow = result.ShouldCreateWindow();
-            if (result.Id())
+            try
             {
-                givenID = result.Id().Value();
+                result = _monarch.ProposeCommandline(args);
+                proposedCommandline = true;
             }
-            givenName = result.WindowName();
-            // TraceLogging doesn't have a good solution for logging an
-            // optional. So we have to repeat the calls here:
-            if (givenID)
+            catch (const winrt::hresult_error& e)
             {
-                TraceLoggingWrite(g_hRemotingProvider,
-                                  "WindowManager_ProposeCommandline",
-                                  TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
-                                  TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
-                                  TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
-                                  TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
-                                  TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+                // We did not successfully ask the king what to do. They
+                // hopefully just died here. That's okay, let's just go ask the
+                // next in the line of succession. At the very worst, we'll find
+                // _us_, (likely last in the line).
+                //
+                // If the king returned some _other_ error here, than lets
+                // bubble that up because that's a real issue.
+                //
+                // I'm checking both these here. I had previously got a
+                // RPC_S_CALL_FAILED about here once.
+                if (e.code() == RPC_SERVER_UNAVAILABLE_HR || e.code() == RPC_CALL_FAILED_HR)
+                {
+                    TraceLoggingWrite(g_hRemotingProvider,
+                                      "WindowManager_proposeToMonarch_kingDied",
+                                      TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
+                                      TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+
+                    // We failed to ask the monarch. It must have died. Try and
+                    // find the real monarch. Don't perform an election, that
+                    // assumes we have a peasant, which we don't yet.
+                    _createMonarchAndCallbacks();
+                    // _createMonarchAndCallbacks will initialize _isKing
+                    if (_isKing)
+                    {
+                        // We became the king. We don't need to ProposeCommandline to ourself, we're just
+                        // going to do it.
+                        //
+                        // Return early, because there's nothing else for us to do here.
+                        TraceLoggingWrite(g_hRemotingProvider,
+                                          "WindowManager_proposeToMonarch_becameKing",
+                                          TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
+                                          TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+
+                        // In WindowManager::ProposeCommandline, had we been the
+                        // king originally, we would have started by setting
+                        // this to true. We became the monarch here, so set it
+                        // here as well.
+                        _shouldCreateWindow = true;
+                        return;
+                    }
+
+                    // Here, we created the new monarch, it wasn't us, so we're
+                    // gonna go through the while loop again and ask the new
+                    // king.
+                    TraceLoggingWrite(g_hRemotingProvider,
+                                      "WindowManager_proposeToMonarch_tryAgain",
+                                      TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
+                                      TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+                }
+                else
+                {
+                    TraceLoggingWrite(g_hRemotingProvider,
+                                      "WindowManager_proposeToMonarch_unexpectedResultFromKing",
+                                      TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
+                                      TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+                    LOG_CAUGHT_EXCEPTION();
+                    throw;
+                }
             }
-            else
+            catch (...)
             {
+                // If the monarch (maybe us) failed for _any other reason_ than
+                // them dying. This IS quite unexpected. Let this bubble out.
                 TraceLoggingWrite(g_hRemotingProvider,
-                                  "WindowManager_ProposeCommandline",
-                                  TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
-                                  TraceLoggingPointer(nullptr, "Id", "No ID provided"),
-                                  TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
+                                  "WindowManager_proposeToMonarch_unexpectedExceptionFromKing",
                                   TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
                                   TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+
+                LOG_CAUGHT_EXCEPTION();
+                throw;
             }
         }
+
+        // Here, the monarch (not us) has replied to the message. Get the
+        // valuables out of the response:
+        _shouldCreateWindow = result.ShouldCreateWindow();
+        if (result.Id())
+        {
+            givenID = result.Id().Value();
+        }
+        givenName = result.WindowName();
+
+        // TraceLogging doesn't have a good solution for logging an
+        // optional. So we have to repeat the calls here:
+        if (givenID)
+        {
+            TraceLoggingWrite(g_hRemotingProvider,
+                              "WindowManager_ProposeCommandline",
+                              TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
+                              TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
+                              TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
+                              TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
+                              TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+        }
         else
+        {
+            TraceLoggingWrite(g_hRemotingProvider,
+                              "WindowManager_ProposeCommandline",
+                              TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
+                              TraceLoggingPointer(nullptr, "Id", "No ID provided"),
+                              TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
+                              TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
+                              TraceLoggingKeyword(TIL_KEYWORD_TRACE));
+        }
+    }
+    void WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args)
+    {
+        // If we're the king, we _definitely_ want to process the arguments, we were
+        // launched with them!
+        //
+        // Otherwise, the King will tell us if we should make a new window
+        _shouldCreateWindow = _isKing;
+        std::optional<uint64_t> givenID;
+        winrt::hstring givenName{};
+        if (!_isKing)
+        {
+            _proposeToMonarch(args, givenID, givenName);
+        }
+
+        // During _proposeToMonarch, it's possible that we found that the king was dead, and we're the new king. Cool! Do this now.
+        if (_isKing)
         {
             // We're the monarch, we don't need to propose anything. We're just
             // going to do it.
@@ -195,6 +299,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
                 _createPeasantThread();
             }
 
+            // This right here will just tell us to stash the args away for the
+            // future. The AppHost hasnt yet set up the callbacks, and the rest
+            // of the app hasn't started at all. We'll note them and come back
+            // later.
             _peasant.ExecuteCommandline(args);
         }
         // Otherwise, we'll do _nothing_.
diff --git a/src/cascadia/Remoting/WindowManager.h b/src/cascadia/Remoting/WindowManager.h
index 0604c34d557..5ea2c56eb6f 100644
--- a/src/cascadia/Remoting/WindowManager.h
+++ b/src/cascadia/Remoting/WindowManager.h
@@ -82,6 +82,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
         void _waitOnMonarchThread();
         void _raiseFindTargetWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
                                              const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
+
+        void _proposeToMonarch(const Remoting::CommandlineArgs& args,
+                               std::optional<uint64_t>& givenID,
+                               winrt::hstring& givenName);
     };
 }
 
diff --git a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp
index 2112c58a6bc..2f0c536837d 100644
--- a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp
+++ b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp
@@ -46,6 +46,11 @@ namespace RemotingUnitTests
         std::function<HRESULT(HWND, BOOL*)> pfnIsWindowOnCurrentVirtualDesktop;
     };
 
+#define DIE                                                                \
+    {                                                                      \
+        throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); \
+    };
+
     // This is a silly helper struct.
     // It will always throw an hresult_error of "RPC server is unavailable" on any of its methods.
     // The monarch uses this particular error code to check for a dead peasant vs another exception.
@@ -57,28 +62,29 @@ namespace RemotingUnitTests
     // class can be used to replace a peasant inside a Monarch, to emulate that
     // peasant process dying. Any time the monarch tries to do something to this
     // peasant, it'll throw an exception.
+
     struct DeadPeasant : implements<DeadPeasant, winrt::Microsoft::Terminal::Remoting::IPeasant>
     {
         DeadPeasant() = default;
-        void AssignID(uint64_t /*id*/) { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        uint64_t GetID() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        winrt::hstring WindowName() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        winrt::hstring ActiveTabTitle() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        void ActiveTabTitle(const winrt::hstring& /*value*/) { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        uint64_t GetPID() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        bool ExecuteCommandline(const Remoting::CommandlineArgs& /*args*/) { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); }
-        void ActivateWindow(const Remoting::WindowActivatedArgs& /*args*/) { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); }
-        void RequestIdentifyWindows() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        void DisplayWindowId() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); }
-        Remoting::WindowActivatedArgs GetLastActivatedArgs() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); }
-        void RequestRename(const Remoting::RenameRequestArgs& /*args*/) { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); }
-        void Summon(const Remoting::SummonWindowBehavior& /*args*/) { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        void RequestShowNotificationIcon() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        void RequestHideNotificationIcon() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        winrt::hstring GetWindowLayout() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        void RequestQuitAll() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
-        void Quit() { throw winrt::hresult_error(winrt::hresult{ (int32_t)0x800706ba }); };
+        void AssignID(uint64_t /*id*/) DIE;
+        uint64_t GetID() DIE;
+        winrt::hstring WindowName() DIE;
+        winrt::hstring ActiveTabTitle() DIE;
+        void ActiveTabTitle(const winrt::hstring& /*value*/) DIE;
+        uint64_t GetPID() DIE;
+        bool ExecuteCommandline(const Remoting::CommandlineArgs& /*args*/) DIE;
+        void ActivateWindow(const Remoting::WindowActivatedArgs& /*args*/) DIE;
+        void RequestIdentifyWindows() DIE;
+        void DisplayWindowId() DIE;
+        Remoting::CommandlineArgs InitialArgs() DIE;
+        Remoting::WindowActivatedArgs GetLastActivatedArgs() DIE;
+        void RequestRename(const Remoting::RenameRequestArgs& /*args*/) DIE;
+        void Summon(const Remoting::SummonWindowBehavior& /*args*/) DIE;
+        void RequestShowNotificationIcon() DIE;
+        void RequestHideNotificationIcon() DIE;
+        winrt::hstring GetWindowLayout() DIE;
+        void RequestQuitAll() DIE;
+        void Quit() DIE;
         TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs);
         TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs);
         TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
@@ -92,6 +98,31 @@ namespace RemotingUnitTests
         TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, Remoting::GetWindowLayoutArgs);
     };
 
+    // Same idea.
+    struct DeadMonarch : implements<DeadMonarch, winrt::Microsoft::Terminal::Remoting::IMonarch>
+    {
+        DeadMonarch() = default;
+        uint64_t GetPID() DIE;
+        uint64_t AddPeasant(Remoting::IPeasant /*peasant*/) DIE;
+        uint64_t GetNumberOfPeasants() DIE;
+        Remoting::ProposeCommandlineResult ProposeCommandline(Remoting::CommandlineArgs /*args*/) DIE;
+        void HandleActivatePeasant(Remoting::WindowActivatedArgs /*args*/) DIE;
+        void SummonWindow(Remoting::SummonWindowSelectionArgs /*args*/) DIE;
+        void SignalClose(uint64_t /*peasantId*/) DIE;
+
+        void SummonAllWindows() DIE;
+        bool DoesQuakeWindowExist() DIE;
+        winrt::Windows::Foundation::Collections::IVectorView<Remoting::PeasantInfo> GetPeasantInfos() DIE;
+        winrt::Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts() DIE;
+
+        TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, Remoting::FindTargetWindowArgs);
+        TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
+        TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
+        TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
+        TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
+        TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, Remoting::QuitAllRequestedArgs);
+    };
+
     class RemotingTests
     {
         BEGIN_TEST_CLASS(RemotingTests)
@@ -145,6 +176,8 @@ namespace RemotingUnitTests
 
         TEST_METHOD(TestSummonAfterWindowClose);
 
+        TEST_METHOD(TestProposeCommandlineWithDeadMonarch);
+
         TEST_CLASS_SETUP(ClassSetup)
         {
             return true;
@@ -2522,4 +2555,48 @@ namespace RemotingUnitTests
         VERIFY_IS_TRUE(args.FoundMatch());
     }
 
+    void RemotingTests::TestProposeCommandlineWithDeadMonarch()
+    {
+        Log::Comment(L"MSFT:32279047 - It's possible for a window to start "
+                     L"right as the monarch is exiting. In that case, "
+                     L"WindowManager relies on getting a "
+                     L"RPC_E_SERVER_UNAVAILABLE when the process dies. ");
+
+        const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
+        const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
+
+        constexpr auto monarch0PID = 12345u;
+
+        auto m0 = make_private<Remoting::implementation::Monarch>(monarch0PID);
+
+        {
+            Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" } };
+            const auto result = m0->ProposeCommandline(args);
+            auto shouldCreateWindow = result.ShouldCreateWindow();
+            VERIFY_IS_TRUE(shouldCreateWindow);
+        }
+
+        auto m1 = make_self<DeadMonarch>();
+        {
+            Remoting::CommandlineArgs args{ { L"wt.exe" }, { L"-Embedding" } };
+
+            try
+            {
+                const auto result = m1->ProposeCommandline(args);
+                VERIFY_IS_FALSE(true, L"This should have thrown");
+            }
+            catch (const winrt::hresult_error& e)
+            {
+                // these two errors are Win32 errors, convert them to HRESULTS so we can actually compare here.
+                constexpr HRESULT RPC_SERVER_UNAVAILABLE_HR = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
+                constexpr HRESULT RPC_CALL_FAILED_HR = HRESULT_FROM_WIN32(RPC_S_CALL_FAILED);
+
+                // This is the same check in WindowManager::_proposeToMonarch.
+                VERIFY_IS_TRUE(e.code() == RPC_SERVER_UNAVAILABLE_HR || e.code() == RPC_CALL_FAILED_HR);
+            }
+            // just don't catch other types of exceptions. They'll take out
+            // TAEF, which will count as a failure.
+        }
+    }
+
 }


Test patch: