Repository: microsoft/terminal
File: src/cascadia/WindowsTerminal/AppHost.cpp (C++)

Code before:
    _window->SetSnapDimensionCallback(std::bind(&winrt::TerminalApp::AppLogic::CalcSnappedDimension,
                                                _logic,
                                                std::placeholders::_1,
                                                std::placeholders::_2));
    _window->MouseScrolled({ this, &AppHost::_WindowMouseWheeled });
    _window->WindowActivated({ this, &AppHost::_WindowActivated });
    _window->HotkeyPressed({ this, &AppHost::_GlobalHotkeyPressed });
    _window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop());
    _window->MakeWindow();

    _windowManager.BecameMonarch({ this, &AppHost::_BecomeMonarch });
    if (_windowManager.IsMonarch())
    {
        _BecomeMonarch(nullptr, nullptr);
    }
}

AppHost::~AppHost()
{
    if (_windowManager.IsMonarch())
    {
        _DestroyTrayIcon();
    }
    else if (_window->IsQuakeWindow())
    {
        _HideTrayIconRequested();
    }

    // destruction order is important for proper teardown here
    _window = nullptr;
    _app.Close();
    _app = nullptr;
}

bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
{
    if (_logic)
    {
        return _logic.OnDirectKeyEvent(vkey, scanCode, down);
    }
    return false;
}

// Method Description:
// - Event handler to update the taskbar progress indicator
// - Upon receiving the event, we ask the underlying logic for the taskbar state/progress values
//   of the last active control
// Arguments:
// - sender: not used
// - args: not used
void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& /*sender*/,

Review comment (suggestion):
This is a bad idea; `_HideTrayIconRequested` is a coroutine that takes an implicit reference to `this`, and you're dispatching it out of the destructor. By the time the `resume_backround` resumes you, `this` will have been destroyed.

This needs to be restructured such that (1) the destructor never uses anything that requires a living `this` to persist after the destructor returns and (2) it is as small as possible :smile:

(Also, there's no guarantee that AppHost *will* be destructed.)

Code after:
    _window->SetSnapDimensionCallback(std::bind(&winrt::TerminalApp::AppLogic::CalcSnappedDimension,
                                                _logic,
                                                std::placeholders::_1,
                                                std::placeholders::_2));
    _window->MouseScrolled({ this, &AppHost::_WindowMouseWheeled });
    _window->WindowActivated({ this, &AppHost::_WindowActivated });
    _window->HotkeyPressed({ this, &AppHost::_GlobalHotkeyPressed });
    _window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop());
    _window->MakeWindow();

    _windowManager.BecameMonarch({ this, &AppHost::_BecomeMonarch });
    if (_windowManager.IsMonarch())
    {
        _BecomeMonarch(nullptr, nullptr);
    }
}

AppHost::~AppHost()
{
    // destruction order is important for proper teardown here
    _window = nullptr;
    _app.Close();
    _app = nullptr;
}

bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
{
    if (_logic)
    {
        return _logic.OnDirectKeyEvent(vkey, scanCode, down);
    }
    return false;
}

// Method Description:
// - Event handler to update the taskbar progress indicator
// - Upon receiving the event, we ask the underlying logic for the taskbar state/progress values
//   of the last active control
// Arguments:
// - sender: not used
// - args: not used
void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& /*sender*/,
                                 const winrt::Windows::Foundation::IInspectable& /*args*/)
{
    if (_logic)
    {
        const auto state = _logic.TaskbarState();
        _window->SetTaskbarProgress(gsl::narrow_cast<size_t>(state.State()),
                                    gsl::narrow_cast<size_t>(state.Progress()));
    }
}