From efe42d17420d3455200ef7af9f45ddb3700b185d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 2 Sep 2021 12:56:27 -0500 Subject: [PATCH 01/12] stunned that this remotely works as well as it does --- .../LocalTests_TerminalApp/SettingsTests.cpp | 245 ++++++++++++++++++ src/cascadia/TerminalApp/TabManagement.cpp | 20 ++ src/cascadia/TerminalApp/TerminalPage.cpp | 126 ++++++++- src/cascadia/TerminalApp/TerminalPage.h | 5 +- .../TerminalSettingsModel/ActionArgs.h | 6 + .../TerminalSettingsModel/ActionArgs.idl | 6 +- .../TerminalSettingsModel/Profile.cpp | 4 + src/cascadia/TerminalSettingsModel/Profile.h | 1 + .../TerminalSettingsModel/Profile.idl | 1 + .../TerminalSettings.cpp | 10 + .../TerminalSettingsModel/TerminalSettings.h | 2 + .../TerminalSettings.idl | 2 + src/cascadia/WindowsTerminal/AppHost.cpp | 11 +- 13 files changed, 432 insertions(+), 7 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index a7cfa529765..69cf818a9bd 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -44,6 +44,8 @@ namespace TerminalAppLocalTests TEST_METHOD(TestIterableColorSchemeCommands); + TEST_METHOD(TestElevateArg); + TEST_CLASS_SETUP(ClassSetup) { return true; @@ -1202,4 +1204,247 @@ namespace TerminalAppLocalTests } } + void SettingsTests::TestElevateArg() + { + const std::string settingsJson{ R"( + { + "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "profiles": [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "commandline": "cmd.exe" + }, + { + "name": "profile1", + "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "elevate": true, + "commandline": "pwsh.exe" + }, + { + "name": "profile2", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", + "elevate": false, + "commandline": "wsl.exe" + } + ], + "keybindings": [ + { "keys": ["ctrl+a"], "command": { "action": "newTab", "profile": "profile0" } }, + { "keys": ["ctrl+b"], "command": { "action": "newTab", "profile": "profile1" } }, + { "keys": ["ctrl+c"], "command": { "action": "newTab", "profile": "profile2" } }, + + { "keys": ["ctrl+d"], "command": { "action": "newTab", "profile": "profile0", "elevate": false } }, + { "keys": ["ctrl+e"], "command": { "action": "newTab", "profile": "profile1", "elevate": false } }, + { "keys": ["ctrl+f"], "command": { "action": "newTab", "profile": "profile2", "elevate": false } }, + + { "keys": ["ctrl+g"], "command": { "action": "newTab", "profile": "profile0", "elevate": true } }, + { "keys": ["ctrl+h"], "command": { "action": "newTab", "profile": "profile1", "elevate": true } }, + { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "elevate": true } }, + ] + })" }; + + const winrt::guid guid0{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-0000-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; + const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") }; + + CascadiaSettings settings{ til::u8u16(settingsJson) }; + + auto keymap = settings.GlobalSettings().KeyMap(); + VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); + + const auto profile2Guid = settings.ActiveProfiles().GetAt(2).Guid(); + VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); + + VERIFY_ARE_EQUAL(9u, keymap.Size()); + + { + KeyChord kc{ true, false, false, static_cast('A') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(false, termSettings.Elevate()); + } + { + KeyChord kc{ true, false, false, static_cast('B') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(true, termSettings.Elevate()); + } + { + KeyChord kc{ true, false, false, static_cast('C') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid2, guid); + VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(false, termSettings.Elevate()); + } + + { + KeyChord kc{ true, false, false, static_cast('D') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(false, termSettings.Elevate()); + } + { + KeyChord kc{ true, false, false, static_cast('E') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(false, termSettings.Elevate()); + } + { + KeyChord kc{ true, false, false, static_cast('F') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid2, guid); + VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(false, termSettings.Elevate()); + } + + { + KeyChord kc{ true, false, false, static_cast('G') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid0, guid); + VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(true, termSettings.Elevate()); + } + { + KeyChord kc{ true, false, false, static_cast('H') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid1, guid); + VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(true, termSettings.Elevate()); + } + { + KeyChord kc{ true, false, false, static_cast('I') }; + auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); + VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); + const auto& realArgs = actionAndArgs.Args().try_as(); + VERIFY_IS_NOT_NULL(realArgs); + // Verify the args have the expected value + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Commandline().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); + VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); + VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); + VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); + VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value()); + + const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); + VERIFY_ARE_EQUAL(guid2, guid); + VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); + VERIFY_ARE_EQUAL(true, termSettings.Elevate()); + } + } + } diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 0a1f91e4616..20d18ba16e7 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -65,6 +65,26 @@ namespace winrt::TerminalApp::implementation const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) }; const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) }; + // Try to handle auto-elevation + const bool requestedElevation = settings.DefaultSettings().Elevate(); + const bool currentlyElevated = _isElevated(); + + // We aren't elevated, but we want to be. + if (requestedElevation && !currentlyElevated) + { + // Manually set the Profile of the NewTerminalArgs to the guid we've + // resolved to. If there was a profile in the NewTerminalArgs, this + // will be that profile's GUID. If there wasn't, then we'll use + // whatever the default profile's GUID is. + + newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid())); + _OpenElevatedWT(newTerminalArgs); + return S_OK; + } + // We can't go in the other direction (elevated->unelevated) + // unfortunately. This seems to be due to Centennial quirks. It works + // unpackaged, but not packaged. + _CreateNewTabWithProfileAndSettings(profile, settings, existingConnection); const uint32_t tabCount = _tabs.Size(); diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 3e11a9eab55..50b5a6afd3c 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -12,6 +12,8 @@ #include "TerminalPage.g.cpp" #include +#include "../WinRTUtils/inc/WtExeUtils.h" + #include "TabRowControl.h" #include "ColorHelper.h" #include "DebugTapConnection.h" @@ -118,6 +120,29 @@ namespace winrt::TerminalApp::implementation _systemRowsToScroll = _ReadSystemRowsToScroll(); } + bool TerminalPage::_isElevated() const noexcept + { + // use C++11 magic statics to make sure we only do this once. + // This won't change over the lifetime of the application + + static const bool isElevated = []() { + // *** THIS IS A SINGLETON *** + auto result = false; + + // GH#2455 - Make sure to try/catch calls to Application::Current, + // because that _won't_ be an instance of TerminalApp::App in the + // LocalTests + try + { + result = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsElevated(); + } + CATCH_LOG(); + return result; + }(); + + return isElevated; + } + void TerminalPage::Create() { // Hookup the key bindings @@ -480,10 +505,43 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - void TerminalPage::_CompleteInitialization() + winrt::fire_and_forget TerminalPage::_CompleteInitialization() { _startupState = StartupState::Initialized; - _InitializedHandlers(*this, nullptr); + + // GH#632 - It's possible that the user tried to create the terminal + // with only one tab, with only an elevated profile. If that happens, + // we'll create _another_ process to host the elevated version of that + // profile. This can happen from the jumplist, or if the default profile + // is `elevate:true`, or from the commandline. + // + // However, we need to make sure to close this window in that scenario. + // Since there aren't any _tabs_ in this window, we won't ever get a + // closed event. So do it manually. + auto weakThis{ get_weak() }; + if (_tabs.Size() == 0) + { + // This is MENTAL. If we exit right away after spawning the elevated + // WT, then ShellExecute might not successfully complete the + // elevation. What's even more, the Terminal will mysteriously crash + // somewhere in XAML land. + // + // So I'm introducing a 5s delay here for the Shell to complete the + // execution, and _then_ close the window. + // + // TODO! There's no way this is the right answer, right? + co_await winrt::resume_background(); + if (auto page{ weakThis.get() }) + { + Sleep(5000); + co_await winrt::resume_foreground(page->Dispatcher(), CoreDispatcherPriority::Normal); + page->_LastTabClosedHandlers(*page, nullptr); + } + } + else + { + _InitializedHandlers(*this, nullptr); + } } // Method Description: @@ -1391,6 +1449,23 @@ namespace winrt::TerminalApp::implementation controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings); } + // Try to handle auto-elevation + const bool requestedElevation = controlSettings.DefaultSettings().Elevate(); + const bool currentlyElevated = _isElevated(); + + // We aren't elevated, but we want to be. + if (requestedElevation && !currentlyElevated) + { + // Manually set the Profile of the NewTerminalArgs to the guid we've + // resolved to. If there was a profile in the NewTerminalArgs, this + // will be that profile's GUID. If there wasn't, then we'll use + // whatever the default profile's GUID is. + + newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid())); + _OpenElevatedWT(newTerminalArgs); + return; + } + const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings()); const float contentWidth = ::base::saturated_cast(_tabContent.ActualWidth()); @@ -3069,4 +3144,51 @@ namespace winrt::TerminalApp::implementation } return profile; } + + // Function Description: + // - Helper to launch a new WT instance elevated. It'll do this by asking + // the shell to elevate the process for us. This might cause a UAC prompt. + // The elevation is performed on a background thread, as to not block the + // UI thread. + // Arguments: + // - newTerminalArgs: A NewTerminalArgs describing the terminal instance + // that should be spawned. The Profile should be filled in with the GUID + // of the profile we want to launch. + // Return Value: + // - + // Important: Don't take the param by reference, since we'll be doing work + // on another thread. + fire_and_forget TerminalPage::_OpenElevatedWT(NewTerminalArgs newTerminalArgs) + { + // Hop to the BG thread + co_await winrt::resume_background(); + + // This will get us the correct exe for dev/preview/release. If you + // don't stick this in a local, it'll get mangled by ShellExecute. I + // have no idea why. + const auto exePath{ GetWtExePath() }; + + // Build the commandline to pass to wt for this set of NewTerminalArgs + winrt::hstring cmdline{ + fmt::format(L"new-tab {}", newTerminalArgs.ToCommandline().c_str()) + }; + + // Build the args to ShellExecuteEx. We need to use ShellExecuteEx so we + // can pass the SEE_MASK_NOASYNC flag. That flag allows us to safely + // call this on the background thread, and have ShellExecute _not_ call + // back to us on the main thread. Without this, if you close the + // Terminal quickly after the UAC prompt, the elevated WT will never + // actually spawn. + SHELLEXECUTEINFOW seInfo{ 0 }; + seInfo.cbSize = sizeof(seInfo); + seInfo.fMask = SEE_MASK_NOASYNC; + seInfo.lpVerb = L"runas"; + seInfo.lpFile = exePath.c_str(); + seInfo.lpParameters = cmdline.c_str(); + seInfo.nShow = SW_SHOWNORMAL; + LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo)); + + co_return; + } + } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index d598d095556..32501402c85 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -320,7 +320,7 @@ namespace winrt::TerminalApp::implementation void _StartInboundListener(); - void _CompleteInitialization(); + winrt::fire_and_forget _CompleteInitialization(); void _FocusActiveControl(IInspectable sender, IInspectable eventArgs); @@ -361,6 +361,9 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept; + bool _isElevated() const noexcept; + winrt::fire_and_forget _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); + #pragma region ActionHandlers // These are all defined in AppActionHandlers.cpp #define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action); diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index 3ae8700393d..b05804e3295 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -110,6 +110,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation ACTION_ARG(winrt::hstring, Profile, L""); ACTION_ARG(Windows::Foundation::IReference, SuppressApplicationTitle, nullptr); ACTION_ARG(winrt::hstring, ColorScheme); + ACTION_ARG(Windows::Foundation::IReference, Elevate, nullptr); static constexpr std::string_view CommandlineKey{ "commandline" }; static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" }; @@ -119,6 +120,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation static constexpr std::string_view ProfileKey{ "profile" }; static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" }; static constexpr std::string_view ColorSchemeKey{ "colorScheme" }; + static constexpr std::string_view ElevateKey{ "elevate" }; public: hstring GenerateName() const; @@ -133,6 +135,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation other.ProfileIndex() == _ProfileIndex && other.Profile() == _Profile && other.SuppressApplicationTitle() == _SuppressApplicationTitle && + other.Elevate() == _Elevate && other.ColorScheme() == _ColorScheme; }; static Model::NewTerminalArgs FromJson(const Json::Value& json) @@ -147,6 +150,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation JsonUtils::GetValueForKey(json, TabColorKey, args->_TabColor); JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle); JsonUtils::GetValueForKey(json, ColorSchemeKey, args->_ColorScheme); + JsonUtils::GetValueForKey(json, ElevateKey, args->_Elevate); return *args; } static Json::Value ToJson(const Model::NewTerminalArgs& val) @@ -165,6 +169,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation JsonUtils::SetValueForKey(json, TabColorKey, args->_TabColor); JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle); JsonUtils::SetValueForKey(json, ColorSchemeKey, args->_ColorScheme); + JsonUtils::SetValueForKey(json, ElevateKey, args->_Elevate); return json; } Model::NewTerminalArgs Copy() const @@ -178,6 +183,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation copy->_Profile = _Profile; copy->_SuppressApplicationTitle = _SuppressApplicationTitle; copy->_ColorScheme = _ColorScheme; + copy->_Elevate = _Elevate; return *copy; } size_t Hash() const diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 03b36815d02..af74c45e5bc 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -117,14 +117,16 @@ namespace Microsoft.Terminal.Settings.Model // ProfileIndex can be null (for "use the default"), so this needs to be // a IReference, so it's nullable Windows.Foundation.IReference ProfileIndex { get; }; - Windows.Foundation.IReference SuppressApplicationTitle; - String ColorScheme; + // This needs to be an optional so that the default value (null) does + // not modifiy whatever the profile's value is (either true or false) + Windows.Foundation.IReference Elevate { get; }; Boolean Equals(NewTerminalArgs other); String GenerateName(); String ToCommandline(); + UInt64 Hash(); }; diff --git a/src/cascadia/TerminalSettingsModel/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp index 338de21ac04..ed8b6c9e270 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -47,6 +47,7 @@ static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" }; static constexpr std::string_view TabColorKey{ "tabColor" }; static constexpr std::string_view BellStyleKey{ "bellStyle" }; static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" }; +static constexpr std::string_view ElevateKey{ "elevate" }; static constexpr std::wstring_view DesktopWallpaperEnum{ L"desktopWallpaper" }; @@ -373,6 +374,7 @@ void Profile::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode); JsonUtils::GetValueForKey(json, TabColorKey, _TabColor); JsonUtils::GetValueForKey(json, BellStyleKey, _BellStyle); + JsonUtils::GetValueForKey(json, ElevateKey, _Elevate); if (json.isMember(JsonKey(UnfocusedAppearanceKey))) { @@ -575,5 +577,7 @@ Json::Value Profile::ToJson() const json[JsonKey(UnfocusedAppearanceKey)] = winrt::get_self(_UnfocusedAppearance.value())->ToJson(); } + JsonUtils::SetValueForKey(json, ElevateKey, _Elevate); + return json; } diff --git a/src/cascadia/TerminalSettingsModel/Profile.h b/src/cascadia/TerminalSettingsModel/Profile.h index c84dadefc94..db6f290f491 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.h +++ b/src/cascadia/TerminalSettingsModel/Profile.h @@ -141,6 +141,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::Profile, bool, AltGrAliasing, true); INHERITABLE_SETTING(Model::Profile, Model::BellStyle, BellStyle, BellStyle::Audible); + INHERITABLE_SETTING(Model::Profile, bool, Elevate, false); INHERITABLE_SETTING(Model::Profile, Model::IAppearanceConfig, UnfocusedAppearance, nullptr); diff --git a/src/cascadia/TerminalSettingsModel/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl index 5ad1ae93314..1d35d5acc7a 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -88,5 +88,6 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_PROFILE_SETTING(Boolean, SnapOnInput); INHERITABLE_PROFILE_SETTING(Boolean, AltGrAliasing); INHERITABLE_PROFILE_SETTING(BellStyle, BellStyle); + INHERITABLE_PROFILE_SETTING(Boolean, Elevate); } } diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index de6b013472c..dbd4197d606 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -155,6 +155,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation defaultSettings.ApplyColorScheme(scheme); } } + // Elevate on NewTerminalArgs is an optional value, so the default + // value (null) doesn't override a profile's value. Note that + // elevate:false in an already elevated terminal does nothing - the + // profile will still be launched elevated. + if (newTerminalArgs.Elevate()) + { + defaultSettings.Elevate(newTerminalArgs.Elevate().Value()); + } } return settingsPair; @@ -304,6 +312,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation const til::color colorRef{ profile.TabColor().Value() }; _TabColor = static_cast(colorRef); } + + _Elevate = profile.Elevate(); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 3744c10573a..f9e8930e624 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -154,6 +154,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, hstring, PixelShaderPath); INHERITABLE_SETTING(Model::TerminalSettings, bool, IntenseIsBold); + INHERITABLE_SETTING(Model::TerminalSettings, bool, Elevate, false); + private: std::optional> _ColorTable; gsl::span _getColorTableImpl(); diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.idl b/src/cascadia/TerminalSettingsModel/TerminalSettings.idl index c40aba55557..8e604e9ba49 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.idl +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.idl @@ -33,5 +33,7 @@ namespace Microsoft.Terminal.Settings.Model void SetParent(TerminalSettings parent); TerminalSettings GetParent(); void ApplyColorScheme(ColorScheme scheme); + + Boolean Elevate; }; } diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index b24c4fd56a3..4eebbb71c0d 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -95,8 +95,15 @@ AppHost::~AppHost() { // destruction order is important for proper teardown here _window = nullptr; - _app.Close(); - _app = nullptr; + try + { + if (_app) + { + _app.Close(); + _app = nullptr; + } + } + CATCH_LOG(); } bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down) From abc0265e713fba3e6d468177b04616af4c71c4de Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 2 Sep 2021 14:41:31 -0500 Subject: [PATCH 02/12] marginally reduce the risk of a merge conflict --- src/cascadia/TerminalApp/TerminalPage.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 32501402c85..869ab85e3b7 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -362,6 +362,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept; bool _isElevated() const noexcept; + winrt::fire_and_forget _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); #pragma region ActionHandlers From 8895e0680b7ac75c53f5f4f792b7d94dd55630ce Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 27 Sep 2021 11:52:37 -0500 Subject: [PATCH 03/12] these are notes, but they're useless who tf am I kidding --- src/cascadia/TerminalApp/TerminalPage.cpp | 33 ++++++++++++++++------- src/cascadia/TerminalApp/TerminalPage.h | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index b6cdea8059c..11968058bf6 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -537,7 +537,7 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - winrt::fire_and_forget TerminalPage::_CompleteInitialization() + void TerminalPage::_CompleteInitialization() { _startupState = StartupState::Initialized; @@ -550,7 +550,7 @@ namespace winrt::TerminalApp::implementation // However, we need to make sure to close this window in that scenario. // Since there aren't any _tabs_ in this window, we won't ever get a // closed event. So do it manually. - auto weakThis{ get_weak() }; + // auto weakThis{ get_weak() }; if (_tabs.Size() == 0) { // This is MENTAL. If we exit right away after spawning the elevated @@ -562,13 +562,14 @@ namespace winrt::TerminalApp::implementation // execution, and _then_ close the window. // // TODO! There's no way this is the right answer, right? - co_await winrt::resume_background(); - if (auto page{ weakThis.get() }) - { - Sleep(5000); - co_await winrt::resume_foreground(page->Dispatcher(), CoreDispatcherPriority::Normal); - page->_LastTabClosedHandlers(*page, nullptr); - } + // co_await winrt::resume_background(); + // if (auto page{ weakThis.get() }) + // { + // Sleep(5000); + // co_await winrt::resume_foreground(page->Dispatcher(), CoreDispatcherPriority::Normal); + // page->_LastTabClosedHandlers(*page, nullptr); + _LastTabClosedHandlers(*this, nullptr); + // } } else { @@ -3574,6 +3575,7 @@ namespace winrt::TerminalApp::implementation { // Hop to the BG thread co_await winrt::resume_background(); + // co_await winrt::resume_foreground(Dispatcher()); // This will get us the correct exe for dev/preview/release. If you // don't stick this in a local, it'll get mangled by ShellExecute. I @@ -3593,14 +3595,25 @@ namespace winrt::TerminalApp::implementation // actually spawn. SHELLEXECUTEINFOW seInfo{ 0 }; seInfo.cbSize = sizeof(seInfo); + seInfo.fMask = SEE_MASK_ASYNCOK; // SEE_MASK_DEFAULT; // SEE_MASK_NOASYNC; + seInfo.fMask = SEE_MASK_DEFAULT; // SEE_MASK_NOASYNC; seInfo.fMask = SEE_MASK_NOASYNC; seInfo.lpVerb = L"runas"; seInfo.lpFile = exePath.c_str(); seInfo.lpParameters = cmdline.c_str(); seInfo.nShow = SW_SHOWNORMAL; LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo)); + co_await winrt::resume_foreground(Dispatcher()); + + // SEE_MASK_ASYNCOK on the main thread (no await): just doesn't work. Exits immediately, no UAC + // SEE_MASK_DEFAULT on the main thread (no await): window waits like 10s each to spawn each child elevated. "works", but it's just hanging the UI thread...? + // SEE_MASK_NOASYNC on the main thread (no await): Like, hangs the origin window, then eventually spawns the new child. Weird. + + // SEE_MASK_ASYNCOK on the bg: + // SEE_MASK_DEFAULT on the bg: + // SEE_MASK_NOASYNC on the bg: Spawns a UAC, but nothing happens - co_return; + // co_return; } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 07de4a5b653..d117b536780 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -334,7 +334,7 @@ namespace winrt::TerminalApp::implementation void _StartInboundListener(); - winrt::fire_and_forget _CompleteInitialization(); + void _CompleteInitialization(); void _FocusActiveControl(IInspectable sender, IInspectable eventArgs); From 9b1e30ba92f227bd70aa6c3ec31f3e2125e1d986 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 27 Sep 2021 12:56:56 -0500 Subject: [PATCH 04/12] I can't believe how dumb this is (or how well it works) --- OpenConsole.sln | 40 +++++++++++ .../CascadiaPackage/CascadiaPackage.wapproj | 1 + src/cascadia/ElevateShim/elevate-shim.cpp | 31 ++++++++ src/cascadia/ElevateShim/elevate-shim.rc | 69 ++++++++++++++++++ src/cascadia/ElevateShim/elevate-shim.vcxproj | 34 +++++++++ src/cascadia/ElevateShim/resource.h | 16 +++++ src/cascadia/TerminalApp/TerminalPage.cpp | 71 +++++++++---------- 7 files changed, 225 insertions(+), 37 deletions(-) create mode 100644 src/cascadia/ElevateShim/elevate-shim.cpp create mode 100644 src/cascadia/ElevateShim/elevate-shim.rc create mode 100644 src/cascadia/ElevateShim/elevate-shim.vcxproj create mode 100644 src/cascadia/ElevateShim/resource.h diff --git a/OpenConsole.sln b/OpenConsole.sln index 493cba041da..d068b78d147 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -336,6 +336,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elevate-shim", "src\cascadia\ElevateShim\elevate-shim.vcxproj", "{416fd703-baa7-4f6e-9361-64f550ec8fca}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Editor", "src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj", "{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}" ProjectSection(ProjectDependencies) = postProject {CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076} @@ -2803,6 +2805,43 @@ Global {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64 {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32 {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|ARM.ActiveCfg = AuditMode|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x64.Build.0 = AuditMode|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x86.Build.0 = AuditMode|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|ARM.ActiveCfg = Debug|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|ARM64.Build.0 = Debug|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x64.ActiveCfg = Debug|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x64.Build.0 = Debug|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x86.ActiveCfg = Debug|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x86.Build.0 = Debug|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|Any CPU.ActiveCfg = Release|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|ARM.ActiveCfg = Release|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|ARM64.ActiveCfg = Release|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|ARM64.Build.0 = Release|ARM64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|DotNet_x64Test.ActiveCfg = Release|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|DotNet_x86Test.ActiveCfg = Release|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x64.ActiveCfg = Release|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x64.Build.0 = Release|x64 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x86.ActiveCfg = Release|Win32 + {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x86.Build.0 = Release|Win32 {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.ActiveCfg = Release|x64 {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Build.0 = Release|x64 {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Deploy.0 = Release|x64 @@ -3420,6 +3459,7 @@ Global {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {4DAF0299-495E-4CD1-A982-9BAC16A45932} {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202} + {416fd703-baa7-4f6e-9361-64f550ec8fca} = {59840756-302F-44DF-AA47-441A9D673202} {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {77875138-BB08-49F9-8BB1-409C2150E0E1} {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {77875138-BB08-49F9-8BB1-409C2150E0E1} {CA5CAD1A-082C-4476-9F33-94B339494076} = {77875138-BB08-49F9-8BB1-409C2150E0E1} diff --git a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj index ba722f24665..c898bfd0b22 100644 --- a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj +++ b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj @@ -68,6 +68,7 @@ + diff --git a/src/cascadia/ElevateShim/elevate-shim.cpp b/src/cascadia/ElevateShim/elevate-shim.cpp new file mode 100644 index 00000000000..6a78959f45d --- /dev/null +++ b/src/cascadia/ElevateShim/elevate-shim.cpp @@ -0,0 +1,31 @@ +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +#pragma warning(suppress : 26461) // we can't change the signature of wWinMain +int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR pCmdLine, int) +{ + std::filesystem::path module{ wil::GetModuleFileNameW(nullptr) }; + + // Cache our name (elevate-shim) + std::wstring ourFilename{ module.filename() }; + + // Swap elevate-shim.exe for WindowsTerminal.exe + module.replace_filename(L"WindowsTerminal.exe"); + + // Go! + SHELLEXECUTEINFOW seInfo{ 0 }; + seInfo.cbSize = sizeof(seInfo); + seInfo.fMask = SEE_MASK_DEFAULT; + seInfo.lpVerb = L"runas"; + seInfo.lpFile = module.c_str(); + seInfo.lpParameters = pCmdLine; + seInfo.nShow = SW_SHOWNORMAL; + LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo)); +} diff --git a/src/cascadia/ElevateShim/elevate-shim.rc b/src/cascadia/ElevateShim/elevate-shim.rc new file mode 100644 index 00000000000..20d7e068e25 --- /dev/null +++ b/src/cascadia/ElevateShim/elevate-shim.rc @@ -0,0 +1,69 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APPICON ICON "..\\..\\..\\res\\terminal.ico" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/cascadia/ElevateShim/elevate-shim.vcxproj b/src/cascadia/ElevateShim/elevate-shim.vcxproj new file mode 100644 index 00000000000..f81353ad368 --- /dev/null +++ b/src/cascadia/ElevateShim/elevate-shim.vcxproj @@ -0,0 +1,34 @@ + + + + {416fd703-baa7-4f6e-9361-64f550ec8fca} + Win32Proj + elevate-shim + elevate-shim + elevate-shim + Application + + + + + + + + + NotUsing + + + + + + + + + + + + + onecore.lib + + + diff --git a/src/cascadia/ElevateShim/resource.h b/src/cascadia/ElevateShim/resource.h new file mode 100644 index 00000000000..62d8839e293 --- /dev/null +++ b/src/cascadia/ElevateShim/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by wt.rc +// +#define IDI_APPICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 11968058bf6..e4533c6a1f5 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3559,10 +3559,10 @@ namespace winrt::TerminalApp::implementation } // Function Description: - // - Helper to launch a new WT instance elevated. It'll do this by asking - // the shell to elevate the process for us. This might cause a UAC prompt. - // The elevation is performed on a background thread, as to not block the - // UI thread. + // - Helper to launch a new WT instance elevated. It'll do this by spawning + // a helper process, who will asking the shell to elevate the process for + // us. This might cause a UAC prompt. The elevation is performed on a + // background thread, as to not block the UI thread. // Arguments: // - newTerminalArgs: A NewTerminalArgs describing the terminal instance // that should be spawned. The Profile should be filled in with the GUID @@ -3575,45 +3575,42 @@ namespace winrt::TerminalApp::implementation { // Hop to the BG thread co_await winrt::resume_background(); - // co_await winrt::resume_foreground(Dispatcher()); - // This will get us the correct exe for dev/preview/release. If you - // don't stick this in a local, it'll get mangled by ShellExecute. I - // have no idea why. - const auto exePath{ GetWtExePath() }; + // This is supremely dumb. We're going to construct the commandline we + // want, then toss it to a helper process called `elevate-shim.exe` that + // happens to live next to us. elevate-shim.exe will be the one to call + // ShellExecute with the args that we want (to elevate the given + // profile). + // + // We can't be the one to call ShellExecute ourselves. ShellExecute + // requires that the calling process stays alive until the child is + // spawned. However, in the case of something like `wt -p + // AlwaysElevateMe`, then the original WT will try to ShellExecute a new + // wt.exe (elevated) and immediately exit, preventing ShellExecute from + // successfully spawning the elevated WT. + + std::filesystem::path exePath = wil::GetModuleFileNameW(nullptr); + exePath.replace_filename(L"elevate-shim.exe"); // Build the commandline to pass to wt for this set of NewTerminalArgs - winrt::hstring cmdline{ + std::wstring cmdline{ fmt::format(L"new-tab {}", newTerminalArgs.ToCommandline().c_str()) }; - // Build the args to ShellExecuteEx. We need to use ShellExecuteEx so we - // can pass the SEE_MASK_NOASYNC flag. That flag allows us to safely - // call this on the background thread, and have ShellExecute _not_ call - // back to us on the main thread. Without this, if you close the - // Terminal quickly after the UAC prompt, the elevated WT will never - // actually spawn. - SHELLEXECUTEINFOW seInfo{ 0 }; - seInfo.cbSize = sizeof(seInfo); - seInfo.fMask = SEE_MASK_ASYNCOK; // SEE_MASK_DEFAULT; // SEE_MASK_NOASYNC; - seInfo.fMask = SEE_MASK_DEFAULT; // SEE_MASK_NOASYNC; - seInfo.fMask = SEE_MASK_NOASYNC; - seInfo.lpVerb = L"runas"; - seInfo.lpFile = exePath.c_str(); - seInfo.lpParameters = cmdline.c_str(); - seInfo.nShow = SW_SHOWNORMAL; - LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo)); - co_await winrt::resume_foreground(Dispatcher()); - - // SEE_MASK_ASYNCOK on the main thread (no await): just doesn't work. Exits immediately, no UAC - // SEE_MASK_DEFAULT on the main thread (no await): window waits like 10s each to spawn each child elevated. "works", but it's just hanging the UI thread...? - // SEE_MASK_NOASYNC on the main thread (no await): Like, hangs the origin window, then eventually spawns the new child. Weird. - - // SEE_MASK_ASYNCOK on the bg: - // SEE_MASK_DEFAULT on the bg: - // SEE_MASK_NOASYNC on the bg: Spawns a UAC, but nothing happens - - // co_return; + wil::unique_process_information pi; + STARTUPINFOW si{}; + si.cb = sizeof(si); + + LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(exePath.c_str(), + cmdline.data(), + nullptr, + nullptr, + FALSE, + 0, + nullptr, + nullptr, + &si, + &pi)); } // Method Description: From 904045bb62379cf1da240b9f0d57a61f7c681adc Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 27 Sep 2021 13:09:40 -0500 Subject: [PATCH 05/12] Tons of comments --- src/cascadia/ElevateShim/elevate-shim.cpp | 27 ++++++++++++++----- src/cascadia/TerminalApp/TerminalPage.cpp | 32 +++++++---------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/cascadia/ElevateShim/elevate-shim.cpp b/src/cascadia/ElevateShim/elevate-shim.cpp index 6a78959f45d..2a20c33af36 100644 --- a/src/cascadia/ElevateShim/elevate-shim.cpp +++ b/src/cascadia/ElevateShim/elevate-shim.cpp @@ -8,14 +8,27 @@ #include #include +// BODGY +// +// If we try to do this in the Terminal itself, then there's a bunch of weird +// things that can go wrong and prevent the elevated Terminal window from +// getting created. Specifically, if the origin Terminal exits right away after +// spawning the elevated WT, then ShellExecute might not successfully complete +// the elevation. What's even more, the Terminal will mysteriously crash +// somewhere in XAML land. +// +// To mitigate this, the Terminal will call into us with the commandline it +// wants elevated. We'll hang around until ShellExecute is finished, so that the +// process can successfully elevate. + #pragma warning(suppress : 26461) // we can't change the signature of wWinMain int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR pCmdLine, int) { - std::filesystem::path module{ wil::GetModuleFileNameW(nullptr) }; - - // Cache our name (elevate-shim) - std::wstring ourFilename{ module.filename() }; + // All of the args passed to us (something like `new-tab -p {guid}`) are in + // pCmdLine + // Get the path to WindowsTerminal.exe, which should live next to us. + std::filesystem::path module{ wil::GetModuleFileNameW(nullptr) }; // Swap elevate-shim.exe for WindowsTerminal.exe module.replace_filename(L"WindowsTerminal.exe"); @@ -23,9 +36,9 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR pCmdLine, int) SHELLEXECUTEINFOW seInfo{ 0 }; seInfo.cbSize = sizeof(seInfo); seInfo.fMask = SEE_MASK_DEFAULT; - seInfo.lpVerb = L"runas"; - seInfo.lpFile = module.c_str(); - seInfo.lpParameters = pCmdLine; + seInfo.lpVerb = L"runas"; // This asks the shell to elevate the process + seInfo.lpFile = module.c_str(); // This is `...\WindowsTerminal.exe` + seInfo.lpParameters = pCmdLine; // This is `new-tab -p {guid}` seInfo.nShow = SW_SHOWNORMAL; LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo)); } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index e4533c6a1f5..d4d00ca3deb 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -550,26 +550,9 @@ namespace winrt::TerminalApp::implementation // However, we need to make sure to close this window in that scenario. // Since there aren't any _tabs_ in this window, we won't ever get a // closed event. So do it manually. - // auto weakThis{ get_weak() }; if (_tabs.Size() == 0) { - // This is MENTAL. If we exit right away after spawning the elevated - // WT, then ShellExecute might not successfully complete the - // elevation. What's even more, the Terminal will mysteriously crash - // somewhere in XAML land. - // - // So I'm introducing a 5s delay here for the Shell to complete the - // execution, and _then_ close the window. - // - // TODO! There's no way this is the right answer, right? - // co_await winrt::resume_background(); - // if (auto page{ weakThis.get() }) - // { - // Sleep(5000); - // co_await winrt::resume_foreground(page->Dispatcher(), CoreDispatcherPriority::Normal); - // page->_LastTabClosedHandlers(*page, nullptr); _LastTabClosedHandlers(*this, nullptr); - // } } else { @@ -3576,11 +3559,12 @@ namespace winrt::TerminalApp::implementation // Hop to the BG thread co_await winrt::resume_background(); - // This is supremely dumb. We're going to construct the commandline we - // want, then toss it to a helper process called `elevate-shim.exe` that - // happens to live next to us. elevate-shim.exe will be the one to call - // ShellExecute with the args that we want (to elevate the given - // profile). + // BODGY + // + // We're going to construct the commandline we want, then toss it to a + // helper process called `elevate-shim.exe` that happens to live next to + // us. elevate-shim.exe will be the one to call ShellExecute with the + // args that we want (to elevate the given profile). // // We can't be the one to call ShellExecute ourselves. ShellExecute // requires that the calling process stays alive until the child is @@ -3611,6 +3595,10 @@ namespace winrt::TerminalApp::implementation nullptr, &si, &pi)); + + // TODO: GH#8592 - It may be useful to pop a Toast here in the original + // Terminal window informing the user that the tab was opened in a new + // window. } // Method Description: From 28bde434d1d9eda01e491b2df545f76e2b9a4fed Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 28 Sep 2021 10:37:29 -0500 Subject: [PATCH 06/12] Works with splitting panes again --- src/cascadia/TerminalApp/TabManagement.cpp | 13 +--- src/cascadia/TerminalApp/TerminalPage.cpp | 75 +++++++++++++++++----- src/cascadia/TerminalApp/TerminalPage.h | 5 +- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 38f38e19c2d..4b6f3152754 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -67,19 +67,8 @@ namespace winrt::TerminalApp::implementation const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) }; // Try to handle auto-elevation - const bool requestedElevation = settings.DefaultSettings().Elevate(); - const bool currentlyElevated = _isElevated(); - - // We aren't elevated, but we want to be. - if (requestedElevation && !currentlyElevated) + if (_maybeElevate(newTerminalArgs, settings, profile)) { - // Manually set the Profile of the NewTerminalArgs to the guid we've - // resolved to. If there was a profile in the NewTerminalArgs, this - // will be that profile's GUID. If there wasn't, then we'll use - // whatever the default profile's GUID is. - - newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid())); - _OpenElevatedWT(newTerminalArgs); return S_OK; } // We can't go in the other direction (elevated->unelevated) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d4d00ca3deb..05a47c3c4f9 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1741,6 +1741,41 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - If the requested settings want us to elevate this new terminal + // instance, and we're not currently elevated, then open the new terminal + // as an elevated instance (using _OpenElevatedWT). Does nothing if we're + // already elevated, or if the control settings don't want to be elevated. + // Arguments: + // - newTerminalArgs: The NewTerminalArgs for this terminal instance + // - controlSettings: The constructed TerminalSettingsCreateResult for this Terminal instance + // - profile: The Profile we're using to launch this Terminal instance + // Return Value: + // - true iff we tossed this request to an elevated window. Callers can use + // this result to early-return if needed. + bool TerminalPage::_maybeElevate(const NewTerminalArgs& newTerminalArgs, + const TerminalSettingsCreateResult& controlSettings, + const Profile& profile) + { + // Try to handle auto-elevation + const bool requestedElevation = controlSettings.DefaultSettings().Elevate(); + const bool currentlyElevated = _isElevated(); + + // We aren't elevated, but we want to be. + if (requestedElevation && !currentlyElevated) + { + // Manually set the Profile of the NewTerminalArgs to the guid we've + // resolved to. If there was a profile in the NewTerminalArgs, this + // will be that profile's GUID. If there wasn't, then we'll use + // whatever the default profile's GUID is. + + newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid())); + _OpenElevatedWT(newTerminalArgs); + return true; + } + return false; + } + // Method Description: // - Split the focused pane either horizontally or vertically, and place the // given TermControl into the newly created pane. @@ -1761,6 +1796,25 @@ namespace winrt::TerminalApp::implementation // Do nothing if no TerminalTab is focused if (!focusedTab) { + // GH#632 + // If there's no tab, but we're requesting a elevated split, + // we still want to toss that over to the elevated window. This is + // for something like + // + // `wtd nt -p "elevated cmd" ; sp -p "elevated cmd"` + // + // We should just make two elevated tabs for that. + + // Note: If the action was a "duplicate pane" action, but there's no + // existing tab to duplicate, then we can't resolve the profile from + // the existing pane. So in that scenario, we won't be able to toss + // anything over to the elevated window. + TerminalSettingsCreateResult controlSettings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, + newTerminalArgs, + *_bindings) }; + Profile profile{ _settings.GetProfileForArgs(newTerminalArgs) }; + _maybeElevate(newTerminalArgs, controlSettings, profile); + return; } @@ -1824,19 +1878,8 @@ namespace winrt::TerminalApp::implementation } // Try to handle auto-elevation - const bool requestedElevation = controlSettings.DefaultSettings().Elevate(); - const bool currentlyElevated = _isElevated(); - - // We aren't elevated, but we want to be. - if (requestedElevation && !currentlyElevated) + if (_maybeElevate(newTerminalArgs, controlSettings, profile)) { - // Manually set the Profile of the NewTerminalArgs to the guid we've - // resolved to. If there was a profile in the NewTerminalArgs, this - // will be that profile's GUID. If there wasn't, then we'll use - // whatever the default profile's GUID is. - - newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid())); - _OpenElevatedWT(newTerminalArgs); return; } @@ -3554,11 +3597,8 @@ namespace winrt::TerminalApp::implementation // - // Important: Don't take the param by reference, since we'll be doing work // on another thread. - fire_and_forget TerminalPage::_OpenElevatedWT(NewTerminalArgs newTerminalArgs) + void TerminalPage::_OpenElevatedWT(NewTerminalArgs newTerminalArgs) { - // Hop to the BG thread - co_await winrt::resume_background(); - // BODGY // // We're going to construct the commandline we want, then toss it to a @@ -3599,6 +3639,9 @@ namespace winrt::TerminalApp::implementation // TODO: GH#8592 - It may be useful to pop a Toast here in the original // Terminal window informing the user that the tab was opened in a new // window. + + // Hop to the BG thread + // co_await winrt::resume_background(); } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index d117b536780..a70686c2359 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -377,7 +377,10 @@ namespace winrt::TerminalApp::implementation bool _isElevated() const noexcept; - winrt::fire_and_forget _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); + bool _maybeElevate(const winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, + const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& controlSettings, + const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); + void _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); bool _shouldPromptForCommandline(const winrt::hstring& cmdline) const; void _adminWarningPrimaryClicked(const winrt::TerminalApp::AdminWarningPlaceholder& sender, From c2b759e90053d2e5c9904aaa3391b3c4b0596243 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 28 Sep 2021 10:44:18 -0500 Subject: [PATCH 07/12] stick these projects in a utils folder because it's getting crowded --- OpenConsole.sln | 87 +++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/OpenConsole.sln b/OpenConsole.sln index d068b78d147..7afd974a612 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -336,7 +336,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elevate-shim", "src\cascadia\ElevateShim\elevate-shim.vcxproj", "{416fd703-baa7-4f6e-9361-64f550ec8fca}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elevate-shim", "src\cascadia\ElevateShim\elevate-shim.vcxproj", "{416FD703-BAA7-4F6E-9361-64F550EC8FCA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Editor", "src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj", "{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}" ProjectSection(ProjectDependencies) = postProject @@ -402,6 +402,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-ms-win-core-synch-l1-2-0", "src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj", "{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{61901E80-E97D-4D61-A9BB-E8F2FDA8B40C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution AuditMode|Any CPU = AuditMode|Any CPU @@ -2805,43 +2807,43 @@ Global {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64 {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32 {506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|ARM.ActiveCfg = AuditMode|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x64.ActiveCfg = AuditMode|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x64.Build.0 = AuditMode|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.AuditMode|x86.Build.0 = AuditMode|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|ARM.ActiveCfg = Debug|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|ARM64.Build.0 = Debug|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x64.ActiveCfg = Debug|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x64.Build.0 = Debug|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x86.ActiveCfg = Debug|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Debug|x86.Build.0 = Debug|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|Any CPU.ActiveCfg = Release|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|ARM.ActiveCfg = Release|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|ARM64.ActiveCfg = Release|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|ARM64.Build.0 = Release|ARM64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|DotNet_x64Test.ActiveCfg = Release|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|DotNet_x86Test.ActiveCfg = Release|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x64.ActiveCfg = Release|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x64.Build.0 = Release|x64 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x86.ActiveCfg = Release|Win32 - {416fd703-baa7-4f6e-9361-64f550ec8fca}.Release|x86.Build.0 = Release|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|ARM.ActiveCfg = AuditMode|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|x64.Build.0 = AuditMode|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.AuditMode|x86.Build.0 = AuditMode|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|ARM.ActiveCfg = Debug|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|ARM64.Build.0 = Debug|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|x64.ActiveCfg = Debug|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|x64.Build.0 = Debug|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|x86.ActiveCfg = Debug|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Debug|x86.Build.0 = Debug|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|Any CPU.ActiveCfg = Release|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|ARM.ActiveCfg = Release|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|ARM64.ActiveCfg = Release|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|ARM64.Build.0 = Release|ARM64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|DotNet_x64Test.ActiveCfg = Release|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|DotNet_x86Test.ActiveCfg = Release|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.ActiveCfg = Release|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32 + {416FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32 {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.ActiveCfg = Release|x64 {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Build.0 = Release|x64 {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Deploy.0 = Release|x64 @@ -3442,7 +3444,7 @@ Global {CA5CAD1A-9A12-429C-B551-8562EC954746} = {59840756-302F-44DF-AA47-441A9D673202} {CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {48D21369-3D7B-4431-9967-24E81292CF63} = {05500DEF-2294-41E3-AF9A-24E580B82836} - {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} = {59840756-302F-44DF-AA47-441A9D673202} + {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {B0AC39D6-7B40-49A9-8202-58549BAE1FB1} = {59840756-302F-44DF-AA47-441A9D673202} {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {A22EC5F6-7851-4B88-AC52-47249D437A52} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} @@ -3455,11 +3457,11 @@ Global {D3EF7B96-CD5E-47C9-B9A9-136259563033} = {04170EEF-983A-4195-BFEF-2321E5E38A1E} {95B136F9-B238-490C-A7C5-5843C1FECAC4} = {05500DEF-2294-41E3-AF9A-24E580B82836} {024052DE-83FB-4653-AEA4-90790D29D5BD} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} - {067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {59840756-302F-44DF-AA47-441A9D673202} + {067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {4DAF0299-495E-4CD1-A982-9BAC16A45932} - {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202} - {416fd703-baa7-4f6e-9361-64f550ec8fca} = {59840756-302F-44DF-AA47-441A9D673202} + {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} + {416FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {77875138-BB08-49F9-8BB1-409C2150E0E1} {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {77875138-BB08-49F9-8BB1-409C2150E0E1} {CA5CAD1A-082C-4476-9F33-94B339494076} = {77875138-BB08-49F9-8BB1-409C2150E0E1} @@ -3478,6 +3480,7 @@ Global {C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {9CF74355-F018-4C19-81AD-9DC6B7F2C6F5} = {89CDCC5C-9F53-4054-97A4-639D99F169CD} + {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} = {59840756-302F-44DF-AA47-441A9D673202} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271} From 4bcdfc3243e096864ece15c7d2a4116f90d1bdff Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 29 Sep 2021 08:01:22 -0500 Subject: [PATCH 08/12] This should have been in the parent --- src/cascadia/TerminalApp/TerminalPage.cpp | 2 +- src/cascadia/TerminalApp/TerminalPage.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d45e35d1d39..feffdabed67 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1771,7 +1771,7 @@ namespace winrt::TerminalApp::implementation { // Try to handle auto-elevation const bool requestedElevation = controlSettings.DefaultSettings().Elevate(); - const bool currentlyElevated = _isElevated(); + const bool currentlyElevated = IsElevated(); // We aren't elevated, but we want to be. if (requestedElevation && !currentlyElevated) diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index ec734a200c8..812df1f5463 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -381,8 +381,6 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept; - bool _isElevated() const noexcept; - bool _maybeElevate(const winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& controlSettings, const winrt::Microsoft::Terminal::Settings::Model::Profile& profile); From 8d7f7262eb72475ec62a8fa84829bd8f21d0994b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 27 Oct 2021 11:07:31 -0500 Subject: [PATCH 09/12] spel --- src/cascadia/TerminalSettingsModel/ActionArgs.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 8335bc5f62b..87149878103 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -123,7 +123,7 @@ namespace Microsoft.Terminal.Settings.Model Windows.Foundation.IReference SuppressApplicationTitle; String ColorScheme; // This needs to be an optional so that the default value (null) does - // not modifiy whatever the profile's value is (either true or false) + // not modify whatever the profile's value is (either true or false) Windows.Foundation.IReference Elevate { get; }; Boolean Equals(NewTerminalArgs other); From 80fe3869549716aa588069c3b228cf061254862e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 28 Oct 2021 07:08:52 -0500 Subject: [PATCH 10/12] tiny nits --- src/cascadia/ElevateShim/elevate-shim.cpp | 3 +++ src/cascadia/TerminalApp/TerminalPage.cpp | 3 --- src/cascadia/TerminalSettingsModel/ActionArgs.h | 10 +++++++++- src/cascadia/TerminalSettingsModel/ActionArgs.idl | 6 ++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/cascadia/ElevateShim/elevate-shim.cpp b/src/cascadia/ElevateShim/elevate-shim.cpp index 2a20c33af36..30670043f03 100644 --- a/src/cascadia/ElevateShim/elevate-shim.cpp +++ b/src/cascadia/ElevateShim/elevate-shim.cpp @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + #include #include diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index c07cdc1f630..51712a6f086 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3683,9 +3683,6 @@ namespace winrt::TerminalApp::implementation // TODO: GH#8592 - It may be useful to pop a Toast here in the original // Terminal window informing the user that the tab was opened in a new // window. - - // Hop to the BG thread - // co_await winrt::resume_background(); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index c9e8b26d8ad..b797dd4d72a 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -193,7 +193,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation } size_t Hash() const { - return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Commandline(), StartingDirectory(), TabTitle(), TabColor(), ProfileIndex(), Profile(), SuppressApplicationTitle(), ColorScheme()); + return ::Microsoft::Terminal::Settings::Model::HashUtils::HashProperty(Commandline(), + StartingDirectory(), + TabTitle(), + TabColor(), + ProfileIndex(), + Profile(), + SuppressApplicationTitle(), + ColorScheme(), + Elevate()); } }; diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 87149878103..049fce52d6c 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -117,6 +117,12 @@ namespace Microsoft.Terminal.Settings.Model String TabTitle; Windows.Foundation.IReference TabColor; String Profile; // Either a GUID or a profile's name if the GUID isn't a match + + // We use IReference<> to treat some args as nullable where null means + // "use the inherited value". See ProfileIndex, + // SuppressApplicationTitle, Elevate. Strings that behave this way just + // use `null` as "use the inherited value". + // ProfileIndex can be null (for "use the default"), so this needs to be // a IReference, so it's nullable Windows.Foundation.IReference ProfileIndex { get; }; From fdd283d7d616181c28ba209f50a3382b8f64377c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 28 Oct 2021 08:29:45 -0500 Subject: [PATCH 11/12] other pr nits, test comments --- .../LocalTests_TerminalApp/SettingsTests.cpp | 17 +++++++++++++++++ .../TerminalSettingsModel/ActionArgs.idl | 1 - src/cascadia/WindowsTerminal/AppHost.cpp | 11 ++--------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index b11fec3e78b..16191eedbfe 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -1323,6 +1323,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(9u, keymap.Size()); { + Log::Comment(L"profile.elevate=omitted, action.elevate=nullopt: don't auto elevate"); + KeyChord kc{ true, false, false, static_cast('A') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1343,6 +1345,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } { + Log::Comment(L"profile.elevate=true, action.elevate=nullopt: DO auto elevate"); + KeyChord kc{ true, false, false, static_cast('B') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1363,6 +1367,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(true, termSettings.Elevate()); } { + Log::Comment(L"profile.elevate=false, action.elevate=nullopt: don't auto elevate"); + KeyChord kc{ true, false, false, static_cast('C') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1384,6 +1390,8 @@ namespace TerminalAppLocalTests } { + Log::Comment(L"profile.elevate=omitted, action.elevate=false: don't auto elevate"); + KeyChord kc{ true, false, false, static_cast('D') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1405,6 +1413,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } { + Log::Comment(L"profile.elevate=true, action.elevate=false: don't auto elevate"); + KeyChord kc{ true, false, false, static_cast('E') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1426,6 +1436,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } { + Log::Comment(L"profile.elevate=false, action.elevate=false: don't auto elevate"); + KeyChord kc{ true, false, false, static_cast('F') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1448,6 +1460,8 @@ namespace TerminalAppLocalTests } { + Log::Comment(L"profile.elevate=omitted, action.elevate=true: DO auto elevate"); + KeyChord kc{ true, false, false, static_cast('G') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1469,6 +1483,7 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(true, termSettings.Elevate()); } { + Log::Comment(L"profile.elevate=true, action.elevate=true: DO auto elevate"); KeyChord kc{ true, false, false, static_cast('H') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); @@ -1490,6 +1505,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(true, termSettings.Elevate()); } { + Log::Comment(L"profile.elevate=false, action.elevate=true: DO auto elevate"); + KeyChord kc{ true, false, false, static_cast('I') }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 049fce52d6c..8506c3354e4 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -135,7 +135,6 @@ namespace Microsoft.Terminal.Settings.Model Boolean Equals(NewTerminalArgs other); String GenerateName(); String ToCommandline(); - UInt64 Hash(); }; diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 2a70aea454e..0ceb487e3ab 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -103,15 +103,8 @@ AppHost::~AppHost() { // destruction order is important for proper teardown here _window = nullptr; - try - { - if (_app) - { - _app.Close(); - _app = nullptr; - } - } - CATCH_LOG(); + _app.Close(); + _app = nullptr; } bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down) From 7a3ec1ed08bf39d839c2327014d7d7f450054f7e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 11 Nov 2021 17:04:25 -0600 Subject: [PATCH 12/12] Fix this test --- .../LocalTests_TerminalApp/SettingsTests.cpp | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index 16191eedbfe..a3dcbb45f4e 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -1271,7 +1271,7 @@ namespace TerminalAppLocalTests void SettingsTests::TestElevateArg() { - const std::string settingsJson{ R"( + static constexpr std::wstring_view settingsJson{ LR"( { "defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", "profiles": [ @@ -1312,20 +1312,20 @@ namespace TerminalAppLocalTests const winrt::guid guid1{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-1111-49a3-80bd-e8fdd045185c}") }; const winrt::guid guid2{ ::Microsoft::Console::Utils::GuidFromString(L"{6239a42c-2222-49a3-80bd-e8fdd045185c}") }; - CascadiaSettings settings{ til::u8u16(settingsJson) }; + CascadiaSettings settings{ settingsJson, {} }; - auto keymap = settings.GlobalSettings().KeyMap(); + auto keymap = settings.GlobalSettings().ActionMap(); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); const auto profile2Guid = settings.ActiveProfiles().GetAt(2).Guid(); VERIFY_ARE_NOT_EQUAL(winrt::guid{}, profile2Guid); - VERIFY_ARE_EQUAL(9u, keymap.Size()); + VERIFY_ARE_EQUAL(9u, keymap.KeyBindings().Size()); { Log::Comment(L"profile.elevate=omitted, action.elevate=nullopt: don't auto elevate"); - KeyChord kc{ true, false, false, static_cast('A') }; + KeyChord kc{ true, false, false, false, static_cast('A'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1339,15 +1339,15 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"profile0", realArgs.TerminalArgs().Profile()); VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } { Log::Comment(L"profile.elevate=true, action.elevate=nullopt: DO auto elevate"); - KeyChord kc{ true, false, false, static_cast('B') }; + KeyChord kc{ true, false, false, false, static_cast('B'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1361,15 +1361,15 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"profile1", realArgs.TerminalArgs().Profile()); VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(true, termSettings.Elevate()); } { Log::Comment(L"profile.elevate=false, action.elevate=nullopt: don't auto elevate"); - KeyChord kc{ true, false, false, static_cast('C') }; + KeyChord kc{ true, false, false, false, static_cast('C'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1383,8 +1383,8 @@ namespace TerminalAppLocalTests VERIFY_ARE_EQUAL(L"profile2", realArgs.TerminalArgs().Profile()); VERIFY_IS_NULL(realArgs.TerminalArgs().Elevate()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid2, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } @@ -1392,7 +1392,7 @@ namespace TerminalAppLocalTests { Log::Comment(L"profile.elevate=omitted, action.elevate=false: don't auto elevate"); - KeyChord kc{ true, false, false, static_cast('D') }; + KeyChord kc{ true, false, false, false, static_cast('D'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1407,15 +1407,15 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } { Log::Comment(L"profile.elevate=true, action.elevate=false: don't auto elevate"); - KeyChord kc{ true, false, false, static_cast('E') }; + KeyChord kc{ true, false, false, false, static_cast('E'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1430,15 +1430,15 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } { Log::Comment(L"profile.elevate=false, action.elevate=false: don't auto elevate"); - KeyChord kc{ true, false, false, static_cast('F') }; + KeyChord kc{ true, false, false, false, static_cast('F'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1453,8 +1453,8 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Elevate().Value()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid2, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(false, termSettings.Elevate()); } @@ -1462,7 +1462,7 @@ namespace TerminalAppLocalTests { Log::Comment(L"profile.elevate=omitted, action.elevate=true: DO auto elevate"); - KeyChord kc{ true, false, false, static_cast('G') }; + KeyChord kc{ true, false, false, false, static_cast('G'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1477,14 +1477,14 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid0, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"cmd.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(true, termSettings.Elevate()); } { Log::Comment(L"profile.elevate=true, action.elevate=true: DO auto elevate"); - KeyChord kc{ true, false, false, static_cast('H') }; + KeyChord kc{ true, false, false, false, static_cast('H'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1499,15 +1499,15 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid1, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"pwsh.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(true, termSettings.Elevate()); } { Log::Comment(L"profile.elevate=false, action.elevate=true: DO auto elevate"); - KeyChord kc{ true, false, false, static_cast('I') }; + KeyChord kc{ true, false, false, false, static_cast('I'), 0 }; auto actionAndArgs = TestUtils::GetActionAndArgs(keymap, kc); VERIFY_ARE_EQUAL(ShortcutAction::NewTab, actionAndArgs.Action()); const auto& realArgs = actionAndArgs.Args().try_as(); @@ -1522,8 +1522,8 @@ namespace TerminalAppLocalTests VERIFY_IS_NOT_NULL(realArgs.TerminalArgs().Elevate()); VERIFY_IS_TRUE(realArgs.TerminalArgs().Elevate().Value()); - const auto [guid, termSettings] = winrt::TerminalApp::implementation::TerminalSettings::BuildSettings(settings, realArgs.TerminalArgs(), nullptr); - VERIFY_ARE_EQUAL(guid2, guid); + const auto termSettingsResult = TerminalSettings::CreateWithNewTerminalArgs(settings, realArgs.TerminalArgs(), nullptr); + const auto termSettings = termSettingsResult.DefaultSettings(); VERIFY_ARE_EQUAL(L"wsl.exe", termSettings.Commandline()); VERIFY_ARE_EQUAL(true, termSettings.Elevate()); }