From 81cdb076466c5ee9ea701366abb2f0e4a3f284c8 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Thu, 20 Nov 2025 20:49:14 +0100 Subject: [PATCH] Separate pruning of elevated/unelevated session buffers (#19546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, launching an unelevated session after an elevated one would delete the latter's persisted buffers, and vice versa of course. Also, elevated buffers didn't have an ACL forbidding access to unelevated users. That's also fixed now. Closes #19526 ## Validation Steps Performed * Unelevated/elevated WT doesn't erase each other's buffers ✅ * Old buffers named `buffer_` are renamed to `elevated_` if needed ✅ --- .github/actions/spelling/expect/expect.txt | 1 + src/buffer/out/textBuffer.cpp | 7 +- src/buffer/out/textBuffer.hpp | 2 +- src/cascadia/TerminalApp/IPaneContent.idl | 3 +- src/cascadia/TerminalApp/TerminalPage.cpp | 34 +++- src/cascadia/TerminalApp/TerminalPage.h | 3 +- .../TerminalApp/TerminalPaneContent.cpp | 8 +- src/cascadia/TerminalApp/TerminalWindow.cpp | 9 +- src/cascadia/TerminalApp/TerminalWindow.h | 3 +- src/cascadia/TerminalApp/TerminalWindow.idl | 4 +- src/cascadia/TerminalControl/ControlCore.cpp | 34 +++- src/cascadia/TerminalControl/ControlCore.h | 2 +- src/cascadia/TerminalControl/TermControl.cpp | 4 +- src/cascadia/TerminalControl/TermControl.h | 2 +- src/cascadia/TerminalControl/TermControl.idl | 2 +- src/cascadia/TerminalCore/Terminal.cpp | 4 +- src/cascadia/TerminalCore/Terminal.hpp | 2 +- .../WindowsTerminal/WindowEmperor.cpp | 166 +++++++++++------- src/cascadia/WindowsTerminal/WindowEmperor.h | 2 +- src/cascadia/inc/cppwinrt_utils.h | 22 +++ 20 files changed, 211 insertions(+), 103 deletions(-) diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt index 3aee8c0272..ede4229f16 100644 --- a/.github/actions/spelling/expect/expect.txt +++ b/.github/actions/spelling/expect/expect.txt @@ -1139,6 +1139,7 @@ NOYIELD NOZORDER NPFS nrcs +NRNW NSTATUS ntapi ntdef diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index 6f0336e8bc..903d3734b1 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -2628,11 +2628,8 @@ void TextBuffer::_AppendRTFText(std::string& contentBuilder, const std::wstring_ } } -void TextBuffer::SerializeToPath(const wchar_t* destination) const +void TextBuffer::SerializeTo(HANDLE handle) const { - const wil::unique_handle file{ CreateFileW(destination, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) }; - THROW_LAST_ERROR_IF(!file); - static constexpr size_t writeThreshold = 32 * 1024; std::wstring buffer; buffer.reserve(writeThreshold + writeThreshold / 2); @@ -2661,7 +2658,7 @@ void TextBuffer::SerializeToPath(const wchar_t* destination) const { const auto fileSize = gsl::narrow(buffer.size() * sizeof(wchar_t)); DWORD bytesWritten = 0; - THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), buffer.data(), fileSize, &bytesWritten, nullptr)); + THROW_IF_WIN32_BOOL_FALSE(WriteFile(handle, buffer.data(), fileSize, &bytesWritten, nullptr)); THROW_WIN32_IF_MSG(ERROR_WRITE_FAULT, bytesWritten != fileSize, "failed to write"); buffer.clear(); } diff --git a/src/buffer/out/textBuffer.hpp b/src/buffer/out/textBuffer.hpp index fca973f50d..be6ee82616 100644 --- a/src/buffer/out/textBuffer.hpp +++ b/src/buffer/out/textBuffer.hpp @@ -288,7 +288,7 @@ public: const bool isIntenseBold, std::function(const TextAttribute&)> GetAttributeColors) const noexcept; - void SerializeToPath(const wchar_t* destination) const; + void SerializeTo(HANDLE handle) const; struct PositionInformation { diff --git a/src/cascadia/TerminalApp/IPaneContent.idl b/src/cascadia/TerminalApp/IPaneContent.idl index ea2e900ca6..f4c6ce1395 100644 --- a/src/cascadia/TerminalApp/IPaneContent.idl +++ b/src/cascadia/TerminalApp/IPaneContent.idl @@ -8,8 +8,7 @@ namespace TerminalApp None, Content, MovePane, - PersistLayout, - PersistAll + Persist, }; runtimeclass BellEventArgs diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index a5a74e140f..cc85d5a561 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2218,7 +2218,7 @@ namespace winrt::TerminalApp::implementation } } - void TerminalPage::PersistState(bool serializeBuffer) + void TerminalPage::PersistState() { // This method may be called for a window even if it hasn't had a tab yet or lost all of them. // We shouldn't persist such windows. @@ -2233,7 +2233,7 @@ namespace winrt::TerminalApp::implementation for (auto tab : _tabs) { auto t = winrt::get_self(tab); - auto tabActions = t->BuildStartupActions(serializeBuffer ? BuildStartupKind::PersistAll : BuildStartupKind::PersistLayout); + auto tabActions = t->BuildStartupActions(BuildStartupKind::Persist); actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end())); } @@ -2319,6 +2319,29 @@ namespace winrt::TerminalApp::implementation CloseWindowRequested.raise(*this, nullptr); } + std::vector TerminalPage::Panes() const + { + std::vector panes; + + for (const auto tab : _tabs) + { + const auto impl = _GetTabImpl(tab); + if (!impl) + { + continue; + } + + impl->GetRootPane()->WalkTree([&](auto&& pane) { + if (auto content = pane->GetContent()) + { + panes.push_back(std::move(content)); + } + }); + } + + return panes; + } + // Method Description: // - Move the viewport of the terminal of the currently focused tab up or // down a number of lines. @@ -3527,9 +3550,12 @@ namespace winrt::TerminalApp::implementation if (hasSessionId) { + using namespace std::string_view_literals; + const auto settingsDir = CascadiaSettings::SettingsDirectory(); - const auto idStr = Utils::GuidToPlainString(sessionId); - const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr); + const auto admin = IsRunningElevated(); + const auto filenamePrefix = admin ? L"elevated_"sv : L"buffer_"sv; + const auto path = fmt::format(FMT_COMPILE(L"{}\\{}{}.txt"), settingsDir, filenamePrefix, sessionId); control.RestoreFromPath(path); } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 8136785134..10b58e175d 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -122,7 +122,8 @@ namespace winrt::TerminalApp::implementation safe_void_coroutine RequestQuit(); safe_void_coroutine CloseWindow(); - void PersistState(bool serializeBuffer); + void PersistState(); + std::vector Panes() const; void ToggleFocusMode(); void ToggleFullscreen(); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.cpp b/src/cascadia/TerminalApp/TerminalPaneContent.cpp index 1ea1b38242..04a03f8b9d 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.cpp +++ b/src/cascadia/TerminalApp/TerminalPaneContent.cpp @@ -140,22 +140,16 @@ namespace winrt::TerminalApp::implementation // "attach existing" rather than a "create" args.ContentId(_control.ContentId()); break; - case BuildStartupKind::PersistAll: + case BuildStartupKind::Persist: { const auto connection = _control.Connection(); const auto id = connection ? connection.SessionId() : winrt::guid{}; - if (id != winrt::guid{}) { - const auto settingsDir = CascadiaSettings::SettingsDirectory(); - const auto idStr = ::Microsoft::Console::Utils::GuidToPlainString(id); - const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr); - _control.PersistToPath(path); args.SessionId(id); } break; } - case BuildStartupKind::PersistLayout: default: break; } diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp index 2bb8cca2cf..e2fc18002e 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.cpp +++ b/src/cascadia/TerminalApp/TerminalWindow.cpp @@ -253,11 +253,11 @@ namespace winrt::TerminalApp::implementation AppLogic::Current()->NotifyRootInitialized(); } - void TerminalWindow::PersistState(bool serializeBuffer) + void TerminalWindow::PersistState() { if (_root) { - _root->PersistState(serializeBuffer); + _root->PersistState(); } } @@ -830,6 +830,11 @@ namespace winrt::TerminalApp::implementation return _root.as(); } + winrt::Windows::Foundation::Collections::IVector TerminalWindow::Panes() const + { + return winrt::single_threaded_vector(_root->Panes()); + } + // Method Description: // - Gets the title of the currently focused terminal control. If there // isn't a control selected for any reason, returns "Terminal" diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h index 68f4c940a3..2f1aad5a7a 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.h +++ b/src/cascadia/TerminalApp/TerminalWindow.h @@ -71,7 +71,7 @@ namespace winrt::TerminalApp::implementation void Create(); - void PersistState(bool serializeBuffer); + void PersistState(); void UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args); @@ -111,6 +111,7 @@ namespace winrt::TerminalApp::implementation float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; Windows::UI::Xaml::UIElement GetRoot() noexcept; + winrt::Windows::Foundation::Collections::IVector Panes() const; hstring Title(); void TitlebarClicked(); diff --git a/src/cascadia/TerminalApp/TerminalWindow.idl b/src/cascadia/TerminalApp/TerminalWindow.idl index 6457a74061..b900522cbf 100644 --- a/src/cascadia/TerminalApp/TerminalWindow.idl +++ b/src/cascadia/TerminalApp/TerminalWindow.idl @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import "IPaneContent.idl"; import "TerminalPage.idl"; import "ShortcutActionDispatch.idl"; @@ -59,9 +60,10 @@ namespace TerminalApp Boolean ShouldImmediatelyHandoffToElevated(); void HandoffToElevated(); - void PersistState(Boolean serializeBuffer); + void PersistState(); Windows.UI.Xaml.UIElement GetRoot(); + IVector Panes { get; }; String Title { get; }; Boolean FocusMode { get; }; diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 644bb2c0bc..948beab9e5 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1815,15 +1815,43 @@ namespace winrt::Microsoft::Terminal::Control::implementation _closeConnection(); } - void ControlCore::PersistToPath(const wchar_t* path) const + void ControlCore::PersistTo(HANDLE handle) const { const auto lock = _terminal->LockForReading(); - _terminal->SerializeMainBuffer(path); + _terminal->SerializeMainBuffer(handle); } void ControlCore::RestoreFromPath(const wchar_t* path) const { - const wil::unique_handle file{ CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) }; + wil::unique_handle file{ CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) }; + + // This block of code exists temporarily to fix buffer dumps that were + // previously persisted as "buffer_" but really should be named "elevated_". + // If loading the properly named file fails, retry with the old name. + if (!file) + { + static constexpr std::wstring_view needle{ L"\\elevated_" }; + + // Check if the path contains "\elevated_", indicating that we're in an elevated session. + const std::wstring_view pathView{ path }; + const auto idx = pathView.find(needle); + + if (idx != std::wstring_view::npos) + { + // If so, try to open the file with "\buffer_" instead, which is what we previously used. + std::wstring altPath{ pathView }; + altPath.replace(idx, needle.size(), L"\\buffer_"); + + file.reset(CreateFileW(altPath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr)); + + // If the alternate file is found, move it to the correct location. + if (file) + { + LOG_IF_WIN32_BOOL_FALSE(MoveFileW(altPath.c_str(), path)); + } + } + } + if (!file) { return; diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 0f911d61e9..d793d88b58 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -153,7 +153,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation void ColorSelection(const Control::SelectionColor& fg, const Control::SelectionColor& bg, Core::MatchMode matchMode); void Close(); - void PersistToPath(const wchar_t* path) const; + void PersistTo(HANDLE handle) const; void RestoreFromPath(const wchar_t* path) const; void ClearQuickFix(); diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index b079dbbc39..a8e993cb91 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -2578,7 +2578,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation _restorePath = std::move(path); } - void TermControl::PersistToPath(const winrt::hstring& path) const + void TermControl::PersistTo(int64_t handle) const { // Don't persist us if we weren't ever initialized. In that case, we // never got an initial size, never instantiated a buffer, and didn't @@ -2590,7 +2590,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // file then. if (_initializedTerminal) { - winrt::get_self(_core)->PersistToPath(path.c_str()); + winrt::get_self(_core)->PersistTo(reinterpret_cast(handle)); } } diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 65276a0056..3db3cec673 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -69,7 +69,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation bool SwitchSelectionEndpoint(); bool ExpandSelectionToWord(); void RestoreFromPath(winrt::hstring path); - void PersistToPath(const winrt::hstring& path) const; + void PersistTo(int64_t handle) const; void OpenCWD(); void Close(); Windows::Foundation::Size CharacterDimensions() const; diff --git a/src/cascadia/TerminalControl/TermControl.idl b/src/cascadia/TerminalControl/TermControl.idl index 34884e8e91..fb99478632 100644 --- a/src/cascadia/TerminalControl/TermControl.idl +++ b/src/cascadia/TerminalControl/TermControl.idl @@ -106,7 +106,7 @@ namespace Microsoft.Terminal.Control Boolean ExpandSelectionToWord(); void ClearBuffer(ClearBufferType clearType); void RestoreFromPath(String path); - void PersistToPath(String path); + void PersistTo(Int64 handle); void OpenCWD(); void Close(); Windows.Foundation.Size CharacterDimensions { get; }; diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 9c3a9b25b7..b6965e3037 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -1523,9 +1523,9 @@ std::wstring Terminal::CurrentCommand() const return _activeBuffer().CurrentCommand(); } -void Terminal::SerializeMainBuffer(const wchar_t* destination) const +void Terminal::SerializeMainBuffer(HANDLE handle) const { - _mainBuffer->SerializeToPath(destination); + _mainBuffer->SerializeTo(handle); } void Terminal::ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode) diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index 5bd67f87e7..33b98151c4 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -127,7 +127,7 @@ public: std::wstring CurrentCommand() const; - void SerializeMainBuffer(const wchar_t* destination) const; + void SerializeMainBuffer(HANDLE handle) const; #pragma region ITerminalApi // These methods are defined in TerminalApi.cpp diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index 2126ad1099..85114486d7 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "AppHost.h" #include "resource.h" @@ -1038,12 +1040,12 @@ void WindowEmperor::_setupSessionPersistence(bool enabled) } _persistStateTimer.Interval(std::chrono::minutes(5)); _persistStateTimer.Tick([&](auto&&, auto&&) { - _persistState(ApplicationState::SharedInstance(), false); + _persistState(ApplicationState::SharedInstance()); }); _persistStateTimer.Start(); } -void WindowEmperor::_persistState(const ApplicationState& state, bool serializeBuffer) const +void WindowEmperor::_persistState(const ApplicationState& state) const { // Calling an `ApplicationState` setter triggers a write to state.json. // With this if condition we avoid an unnecessary write when persistence is disabled. @@ -1052,11 +1054,11 @@ void WindowEmperor::_persistState(const ApplicationState& state, bool serializeB state.PersistedWindowLayouts(nullptr); } - if (_app.Logic().Settings().GlobalSettings().ShouldUsePersistedLayout()) + if (_app.Logic().Settings().GlobalSettings().FirstWindowPreference() != FirstWindowPreference::DefaultProfile) { for (const auto& w : _windows) { - w->Logic().PersistState(serializeBuffer); + w->Logic().PersistState(); } } @@ -1066,6 +1068,8 @@ void WindowEmperor::_persistState(const ApplicationState& state, bool serializeB void WindowEmperor::_finalizeSessionPersistence() const { + using namespace std::string_view_literals; + if (_skipPersistence) { // We received WM_ENDSESSION and persisted the state. @@ -1075,78 +1079,106 @@ void WindowEmperor::_finalizeSessionPersistence() const const auto state = ApplicationState::SharedInstance(); - _persistState(state, _app.Logic().Settings().GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedLayoutAndContent); + _persistState(state); + const auto firstWindowPreference = _app.Logic().Settings().GlobalSettings().FirstWindowPreference(); + const auto wantsPersistence = firstWindowPreference != FirstWindowPreference::DefaultProfile; + + // If we neither need a cleanup nor want to persist, we can exit early. + if (!_needsPersistenceCleanup && !wantsPersistence) + { + return; + } + + const std::filesystem::path settingsDirectory{ std::wstring_view{ CascadiaSettings::SettingsDirectory() } }; + const auto admin = _app.Logic().IsRunningElevated(); + const auto filenamePrefix = admin ? L"elevated_"sv : L"buffer_"sv; + const auto persistBuffers = firstWindowPreference == FirstWindowPreference::PersistedLayoutAndContent; + std::unordered_set bufferFilenames; + + if (persistBuffers) + { + // If the app is running elevated, we create files with a mandatory + // integrity label (ML) of "High" (HI) for reading and writing (NR, NW). + wil::unique_hlocal_security_descriptor sd; + SECURITY_ATTRIBUTES sa{}; + if (admin) + { + unsigned long cb; + THROW_IF_WIN32_BOOL_FALSE(ConvertStringSecurityDescriptorToSecurityDescriptorW(L"S:(ML;;NRNW;;;HI)", SDDL_REVISION_1, wil::out_param_ptr(sd), &cb)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = sd.get(); + } + + // Persist all terminal buffers to "buffer_{guid}.txt" files. + // We remember the filenames so that we can clean up old ones later. + for (const auto& w : _windows) + { + const auto panes = w->Logic().Panes(); + for (const auto pane : panes) + { + try + { + const auto term = pane.try_as(); + if (!term) + { + continue; + } + const auto control = term.GetTermControl(); + if (!control) + { + continue; + } + const auto connection = control.Connection(); + if (!connection) + { + continue; + } + const auto sessionId = connection.SessionId(); + if (sessionId == winrt::guid{}) + { + continue; + } + + auto filename = fmt::format(FMT_COMPILE(L"{}{}.txt"), filenamePrefix, sessionId); + const auto path = settingsDirectory / filename; + + if (wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) }) + { + control.PersistTo(reinterpret_cast(file.get())); + bufferFilenames.emplace(std::move(filename)); + } + } + CATCH_LOG(); + } + } + } + + // Now remove the "buffer_{guid}.txt" files that shouldn't be there. if (_needsPersistenceCleanup) { - // Get the "buffer_{guid}.txt" files that we expect to be there - std::unordered_set sessionIds; - if (const auto layouts = state.PersistedWindowLayouts()) + const auto filter = fmt::format(FMT_COMPILE(L"{}\\{}*"), settingsDirectory.native(), filenamePrefix); + + // This could also use std::filesystem::directory_iterator. + // I was just slightly bothered by how it doesn't have a O(1) .filename() + // function, even though the underlying Win32 APIs provide it for free. + // Both work fine. + WIN32_FIND_DATAW ffd; + const wil::unique_hfind handle{ FindFirstFileExW(filter.c_str(), FindExInfoBasic, &ffd, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH) }; + if (!handle) { - for (const auto& windowLayout : layouts) - { - for (const auto& actionAndArgs : windowLayout.TabLayout()) - { - const auto args = actionAndArgs.Args(); - NewTerminalArgs terminalArgs{ nullptr }; - - if (const auto tabArgs = args.try_as()) - { - terminalArgs = tabArgs.ContentArgs().try_as(); - } - else if (const auto paneArgs = args.try_as()) - { - terminalArgs = paneArgs.ContentArgs().try_as(); - } - - if (terminalArgs) - { - sessionIds.emplace(terminalArgs.SessionId()); - } - } - } + return; } - // Remove the "buffer_{guid}.txt" files that shouldn't be there - // e.g. "buffer_FD40D746-163E-444C-B9B2-6A3EA2B26722.txt" + do { - const std::filesystem::path settingsDirectory{ std::wstring_view{ CascadiaSettings::SettingsDirectory() } }; - const auto filter = settingsDirectory / L"buffer_*"; - WIN32_FIND_DATAW ffd; - - // This could also use std::filesystem::directory_iterator. - // I was just slightly bothered by how it doesn't have a O(1) .filename() - // function, even though the underlying Win32 APIs provide it for free. - // Both work fine. - const wil::unique_hfind handle{ FindFirstFileExW(filter.c_str(), FindExInfoBasic, &ffd, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH) }; - if (!handle) + const auto nameLen = wcsnlen_s(&ffd.cFileName[0], ARRAYSIZE(ffd.cFileName)); + const std::wstring_view filename{ &ffd.cFileName[0], nameLen }; + if (!bufferFilenames.contains(filename)) { - return; + std::filesystem::remove(settingsDirectory / filename); } - - do - { - const auto nameLen = wcsnlen_s(&ffd.cFileName[0], ARRAYSIZE(ffd.cFileName)); - const std::wstring_view name{ &ffd.cFileName[0], nameLen }; - - if (nameLen != 47) - { - continue; - } - - wchar_t guidStr[39]; - guidStr[0] = L'{'; - memcpy(&guidStr[1], name.data() + 7, 36 * sizeof(wchar_t)); - guidStr[37] = L'}'; - guidStr[38] = L'\0'; - - const auto id = Utils::GuidFromString(&guidStr[0]); - if (!sessionIds.contains(id)) - { - std::filesystem::remove(settingsDirectory / name); - } - } while (FindNextFileW(handle.get(), &ffd)); - } + } while (FindNextFileW(handle.get(), &ffd)); } } diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.h b/src/cascadia/WindowsTerminal/WindowEmperor.h index c64b8c5fef..5e2801276c 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.h +++ b/src/cascadia/WindowsTerminal/WindowEmperor.h @@ -65,7 +65,7 @@ private: void _unregisterHotKey(int index) noexcept; void _setupGlobalHotkeys(); void _setupSessionPersistence(bool enabled); - void _persistState(const winrt::Microsoft::Terminal::Settings::Model::ApplicationState& state, bool serializeBuffer) const; + void _persistState(const winrt::Microsoft::Terminal::Settings::Model::ApplicationState& state) const; void _finalizeSessionPersistence() const; void _checkWindowsForNotificationIcon(); diff --git a/src/cascadia/inc/cppwinrt_utils.h b/src/cascadia/inc/cppwinrt_utils.h index e7a8527818..34a2f75810 100644 --- a/src/cascadia/inc/cppwinrt_utils.h +++ b/src/cascadia/inc/cppwinrt_utils.h @@ -74,6 +74,28 @@ struct fmt::formatter : fmt::formatter +struct fmt::formatter : fmt::formatter +{ + auto format(const winrt::guid& value, auto& ctx) const + { + return fmt::format_to( + ctx.out(), + L"{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}", + value.Data1, + value.Data2, + value.Data3, + value.Data4[0], + value.Data4[1], + value.Data4[2], + value.Data4[3], + value.Data4[4], + value.Data4[5], + value.Data4[6], + value.Data4[7]); + } +}; + // This is a helper macro for both declaring the signature of an event, and // defining the body. Winrt events need a method for adding a callback to the // event and removing the callback. This macro will both declare the method