Repository: microsoft/terminal (language: cpp)

Issue:
Multiple 'Settings' entries on title bar context menu. Crashes Terminal.
### Windows Terminal version

1.18.2822.0

### Windows build number

10.0.19045.0

### Other Software

_No response_

### Steps to reproduce

Not sure what is triggering it unfortunately.

### Expected Behavior

_No response_

### Actual Behavior

I've noticed that sometimes, after using Terminal for some time, the right-click context menu on the titlebar ends up getting multiple `Settings` entries. When I click on one of them, Terminal crashes. When there's only one it doesn't crash; it opens the Settings panel as it should.

See the video below. Again this is after using Terminal for some time, opening and closing windows, etc. I don't know how to reproduce the bug consistently.

https://github.com/microsoft/terminal/assets/11712728/4e8e324e-8934-42c0-8d48-b73f488d32fd

I've seen it before with as many as six of these `Settings` entries.

The crash in the above video corresponds to this event (if it helps):

    Faulting application name: WindowsTerminal.exe, version: 1.18.2310.9002, time stamp: 0x65248b0f
    Faulting module name: TerminalApp.dll, version: 1.18.2310.9002, time stamp: 0x65248aa8
    Exception code: 0xc0000005
    Fault offset: 0x0000000000050c6a
    Faulting process ID: 0x4d8c
    Faulting application start time: 0x01da047ff2360b38
    Faulting application path: C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.18.2822.0_x64__8wekyb3d8bbwe\WindowsTerminal.exe
    Faulting module path: C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.18.2822.0_x64__8wekyb3d8bbwe\TerminalApp.dll
    Report ID: 4ed86fa0-563b-4b67-bb0e-de7b5ea21887
    Faulting package full name: Microsoft.WindowsTerminal_1.18.2822.0_x64__8wekyb3d8bbwe
    Faulting package-relative application ID: App

I'm not sure if it's related to my other bug report #16100.


Discussion / hints:
I'm gonna guess this is also a window refrigeration bug. 

I'd guess that the problem code is `AppHost::_SystemMenuChangeRequested` not getting called to remove the old entries before refrigeration.

Oh it definitely is. `TerminalWindow` only ever adds the settings entry when it gets created. `AppHost` however needs to clear that old entry out before we refrigerate the HWND. The old entries end up sticking around, which is why the old entries will explode the Terminal. 

Fix patch:
diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp
index 36d47211b79..5af3a80d50a 100644
--- a/src/cascadia/WindowsTerminal/AppHost.cpp
+++ b/src/cascadia/WindowsTerminal/AppHost.cpp
@@ -484,7 +484,7 @@ void AppHost::_revokeWindowCallbacks()
     // I suspect WinUI wouldn't like that very much. As such unregister all event handlers first.
     _revokers = {};
     _showHideWindowThrottler.reset();
-
+    _stopFrameTimer();
     _revokeWindowCallbacks();
 
     // DO NOT CLOSE THE WINDOW
diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp
index 9bea05acfe9..d7934ea3012 100644
--- a/src/cascadia/WindowsTerminal/IslandWindow.cpp
+++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp
@@ -73,6 +73,8 @@ void IslandWindow::Refrigerate() noexcept
     // This pointer will get re-set in _warmInitialize
     SetWindowLongPtr(_window.get(), GWLP_USERDATA, 0);
 
+    _resetSystemMenu();
+
     _pfnCreateCallback = nullptr;
     _pfnSnapDimensionCallback = nullptr;
 
@@ -1917,6 +1919,12 @@ void IslandWindow::RemoveFromSystemMenu(const winrt::hstring& itemLabel)
     _systemMenuItems.erase(it->first);
 }
 
+void IslandWindow::_resetSystemMenu()
+{
+    // GetSystemMenu(..., true) will revert the menu to the default state.
+    GetSystemMenu(_window.get(), TRUE);
+}
+
 void IslandWindow::UseDarkTheme(const bool v)
 {
     const BOOL attribute = v ? TRUE : FALSE;
diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h
index eee013c529a..b0aaf0b0ae3 100644
--- a/src/cascadia/WindowsTerminal/IslandWindow.h
+++ b/src/cascadia/WindowsTerminal/IslandWindow.h
@@ -159,6 +159,7 @@ class IslandWindow :
 
     std::unordered_map<UINT, SystemMenuItemInfo> _systemMenuItems;
     UINT _systemMenuNextItemId;
+    void _resetSystemMenu();
 
 private:
     // This minimum width allows for width the tabs fit


Test patch: