From 36539cfa47d1b5f3a3b0bf44f7bdcb057aa08e95 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 16 Dec 2020 16:03:23 -0600 Subject: [PATCH] This won't work, but I'm committing this becaus I finally got it to compile a String[] --- src/cascadia/Remoting/CommandlineArgs.cpp | 20 ++++++ src/cascadia/Remoting/CommandlineArgs.h | 39 +++++++++++ .../Microsoft.Terminal.RemotingLib.vcxproj | 8 ++- src/cascadia/Remoting/Monarch.cpp | 13 ++-- src/cascadia/Remoting/Peasant.cpp | 33 ++++++--- src/cascadia/Remoting/Peasant.h | 11 ++- src/cascadia/Remoting/Peasant.idl | 15 +++- src/cascadia/Remoting/WindowManager.cpp | 70 +++++++++++++++---- src/cascadia/Remoting/WindowManager.h | 11 ++- src/cascadia/Remoting/WindowManager.idl | 4 +- src/cascadia/WindowsTerminal/AppHost.cpp | 34 +++++++-- 11 files changed, 217 insertions(+), 41 deletions(-) create mode 100644 src/cascadia/Remoting/CommandlineArgs.cpp create mode 100644 src/cascadia/Remoting/CommandlineArgs.h diff --git a/src/cascadia/Remoting/CommandlineArgs.cpp b/src/cascadia/Remoting/CommandlineArgs.cpp new file mode 100644 index 00000000000..e3c31cd2a31 --- /dev/null +++ b/src/cascadia/Remoting/CommandlineArgs.cpp @@ -0,0 +1,20 @@ +#include "pch.h" + +#include "CommandlineArgs.h" +#include "CommandlineArgs.g.cpp" +using namespace winrt; +using namespace winrt::Microsoft::Terminal; +using namespace winrt::Windows::Foundation; + +namespace winrt::Microsoft::Terminal::Remoting::implementation +{ + void CommandlineArgs::Args(winrt::array_view const& value) + { + _args = { value.begin(), value.end() }; + } + + winrt::com_array CommandlineArgs::Args() + { + return winrt::com_array{ _args.begin(), _args.end() }; + } +} diff --git a/src/cascadia/Remoting/CommandlineArgs.h b/src/cascadia/Remoting/CommandlineArgs.h new file mode 100644 index 00000000000..159071854f2 --- /dev/null +++ b/src/cascadia/Remoting/CommandlineArgs.h @@ -0,0 +1,39 @@ +#pragma once + +#include "CommandlineArgs.g.h" +#include "../cascadia/inc/cppwinrt_utils.h" + +namespace winrt::Microsoft::Terminal::Remoting::implementation +{ + struct CommandlineArgs : public CommandlineArgsT + { + public: + CommandlineArgs() : + _args{}, + _cwd{ L"" } + { + } + + CommandlineArgs(const winrt::array_view& args, + winrt::hstring currentDirectory) : + _args{ args.begin(), args.end() }, + _cwd{ currentDirectory } + { + } + + winrt::hstring CurrentDirectory() { return _cwd; }; + + void Args(winrt::array_view const& value); + winrt::com_array Args(); + + private: + winrt::com_array _args; + winrt::hstring _cwd; + }; + +} + +namespace winrt::Microsoft::Terminal::Remoting::factory_implementation +{ + BASIC_FACTORY(CommandlineArgs); +} diff --git a/src/cascadia/Remoting/Microsoft.Terminal.RemotingLib.vcxproj b/src/cascadia/Remoting/Microsoft.Terminal.RemotingLib.vcxproj index ad736bd6d32..b5d5355e414 100644 --- a/src/cascadia/Remoting/Microsoft.Terminal.RemotingLib.vcxproj +++ b/src/cascadia/Remoting/Microsoft.Terminal.RemotingLib.vcxproj @@ -25,7 +25,10 @@ Peasant.idl - WindowManager .idl + WindowManager.idl + + + Peasant.idl @@ -42,6 +45,9 @@ WindowManager.idl + + Peasant.idl + diff --git a/src/cascadia/Remoting/Monarch.cpp b/src/cascadia/Remoting/Monarch.cpp index 6a74171004f..888dbade666 100644 --- a/src/cascadia/Remoting/Monarch.cpp +++ b/src/cascadia/Remoting/Monarch.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "Monarch.h" +#include "CommandlineArgs.h" #include "Monarch.g.cpp" #include "../../types/inc/utils.hpp" @@ -91,7 +92,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation _setMostRecentPeasant(_thisPeasantID); } - bool Monarch::ProposeCommandline(array_view args, winrt::hstring cwd) + bool Monarch::ProposeCommandline(array_view args, + winrt::hstring cwd) { auto argsProcessed = 0; std::wstring fullCmdline; @@ -125,7 +127,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation printf("Session 0 is actually #%llu\n", _mostRecentPeasant); if (auto mruPeasant = _getPeasant(_mostRecentPeasant)) { - mruPeasant.ExecuteCommandline(args, cwd); + auto eventArgs = winrt::make_self(args, cwd); + mruPeasant.ExecuteCommandline(*eventArgs); createNewWindow = false; } } @@ -133,7 +136,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation { if (auto otherPeasant = _getPeasant(sessionId)) { - otherPeasant.ExecuteCommandline(args, cwd); + auto eventArgs = winrt::make_self(args, cwd); + otherPeasant.ExecuteCommandline(*eventArgs); createNewWindow = false; } else @@ -147,7 +151,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation { if (auto mruPeasant = _getPeasant(_mostRecentPeasant)) { - mruPeasant.ExecuteCommandline(args, cwd); + auto eventArgs = winrt::make_self(args, cwd); + mruPeasant.ExecuteCommandline(*eventArgs); createNewWindow = false; } } diff --git a/src/cascadia/Remoting/Peasant.cpp b/src/cascadia/Remoting/Peasant.cpp index 30b10b5f8f9..cd8b98fe55a 100644 --- a/src/cascadia/Remoting/Peasant.cpp +++ b/src/cascadia/Remoting/Peasant.cpp @@ -1,10 +1,11 @@ #include "pch.h" #include "Peasant.h" - +#include "CommandlineArgs.h" #include "Peasant.g.cpp" #include "../../types/inc/utils.hpp" using namespace winrt; +using namespace winrt::Microsoft::Terminal; using namespace winrt::Windows::Foundation; using namespace ::Microsoft::Console; @@ -28,18 +29,25 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation return GetCurrentProcessId(); } - bool Peasant::ExecuteCommandline(winrt::array_view args, winrt::hstring currentDirectory) + bool Peasant::ExecuteCommandline(const Remoting::CommandlineArgs& args) { - auto argsProcessed = 0; - std::wstring fullCmdline; - for (const auto& arg : args) + if (_initialArgs == nullptr) { - fullCmdline += argsProcessed++ == 0 ? L"sample.exe" : arg; - fullCmdline += L" "; + _initialArgs = args; } - wprintf(L"\x1b[32mExecuted Commandline\x1b[m: \""); - wprintf(fullCmdline.c_str()); - wprintf(L"\"\n"); + + _ExecuteCommandlineRequestedHandlers(*this, args); + + // auto argsProcessed = 0; + // std::wstring fullCmdline; + // for (const auto& arg : args) + // { + // fullCmdline += argsProcessed++ == 0 ? L"sample.exe" : arg; + // fullCmdline += L" "; + // } + // wprintf(L"\x1b[32mExecuted Commandline\x1b[m: \""); + // wprintf(fullCmdline.c_str()); + // wprintf(L"\"\n"); return true; } @@ -48,4 +56,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation _WindowActivatedHandlers(*this, nullptr); } + Remoting::CommandlineArgs Peasant::InitialArgs() + { + return _initialArgs; + } + } diff --git a/src/cascadia/Remoting/Peasant.h b/src/cascadia/Remoting/Peasant.h index 31da53ff5c5..df4db13b529 100644 --- a/src/cascadia/Remoting/Peasant.h +++ b/src/cascadia/Remoting/Peasant.h @@ -13,15 +13,20 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation uint64_t GetID(); uint64_t GetPID(); - bool ExecuteCommandline(winrt::array_view args, - winrt::hstring currentDirectory); + bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args); void raiseActivatedEvent(); - + winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs(); TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs); private: uint64_t _id{ 0 }; + + winrt::Microsoft::Terminal::Remoting::CommandlineArgs _initialArgs; //{ nullptr }; + + // array_view _args; + // winrt::hstring _cwd; }; } diff --git a/src/cascadia/Remoting/Peasant.idl b/src/cascadia/Remoting/Peasant.idl index b351448183a..7ffb9512170 100644 --- a/src/cascadia/Remoting/Peasant.idl +++ b/src/cascadia/Remoting/Peasant.idl @@ -2,13 +2,26 @@ namespace Microsoft.Terminal.Remoting { + + runtimeclass CommandlineArgs + { + CommandlineArgs(); + CommandlineArgs(String[] args, String cwd); + + String[] Args { get; set; }; + String CurrentDirectory(); + }; + interface IPeasant { + CommandlineArgs InitialArgs { get; }; + void AssignID(UInt64 id); UInt64 GetID(); UInt64 GetPID(); - Boolean ExecuteCommandline(String[] args, String currentDirectory); + Boolean ExecuteCommandline(CommandlineArgs args); event Windows.Foundation.TypedEventHandler WindowActivated; + event Windows.Foundation.TypedEventHandler ExecuteCommandlineRequested; }; [default_interface] runtimeclass Peasant : IPeasant diff --git a/src/cascadia/Remoting/WindowManager.cpp b/src/cascadia/Remoting/WindowManager.cpp index 87e2b482b3e..ddc0d85989a 100644 --- a/src/cascadia/Remoting/WindowManager.cpp +++ b/src/cascadia/Remoting/WindowManager.cpp @@ -1,11 +1,13 @@ #include "pch.h" #include "WindowManager.h" #include "MonarchFactory.h" +#include "CommandlineArgs.h" #include "WindowManager.g.cpp" #include "../../types/inc/utils.hpp" using namespace winrt; +using namespace winrt::Microsoft::Terminal; using namespace winrt::Windows::Foundation; using namespace ::Microsoft::Console; @@ -13,8 +15,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation { WindowManager::WindowManager() { - _RegisterAsMonarch(); - _CreateMonarch(); + _registerAsMonarch(); + _createMonarch(); } WindowManager::~WindowManager() { @@ -26,8 +28,29 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation _registrationHostClass = 0; } - void WindowManager::ProposeCommandline() + void WindowManager::ProposeCommandline(array_view args, const winrt::hstring cwd) { + const bool isKing = _areWeTheKing(); + // If we're the king, we _definitely_ want to process the arguments, we were + // launched with them! + // + // Otherwise, the King will tell us if we should make a new window + const bool createNewWindow = isKing || + _monarch.ProposeCommandline(args, cwd); + + if (createNewWindow) + { + _createOurPeasant(); + + auto eventArgs = winrt::make_self(args, cwd); + _peasant.ExecuteCommandline(*eventArgs); + _shouldCreateWindow = false; + } + else + { + // printf("The Monarch instructed us to not create a new window. We'll be exiting now.\n"); + } + _shouldCreateWindow = true; } @@ -36,7 +59,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation return _shouldCreateWindow; } - void WindowManager::_RegisterAsMonarch() + void WindowManager::_registerAsMonarch() { winrt::check_hresult(CoRegisterClassObject(Monarch_clsid, winrt::make<::MonarchFactory>().get(), @@ -45,7 +68,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation &_registrationHostClass)); } - void WindowManager::_CreateMonarch() + void WindowManager::_createMonarch() { // Heads up! This only works because we're using // "metadata-based-marshalling" for our WinRT types. THat means the OS is @@ -55,13 +78,36 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation // // * If we're running unpackaged: the .winmd but be a sibling of the .exe // * If we're running packaged: the .winmd must be in the package root - _monarch = create_instance(Monarch_clsid, - CLSCTX_LOCAL_SERVER); + _monarch = create_instance(Monarch_clsid, + CLSCTX_LOCAL_SERVER); + } + + bool WindowManager::_areWeTheKing() + { + auto kingPID = _monarch.GetPID(); + auto ourPID = GetCurrentProcessId(); + return (ourPID == kingPID); + } + + Remoting::IPeasant WindowManager::_createOurPeasant() + { + auto p = winrt::make_self(); + _peasant = *p; + auto ourID = _monarch.AddPeasant(_peasant); + ourID; + // printf("The monarch assigned us the ID %llu\n", ourID); + + // if (areWeTheKing()) + // { + // remindKingWhoTheyAre(*peasant); + // } + + return _peasant; + } + + Remoting::Peasant WindowManager::CurrentWindow() + { + return _peasant; } - // bool AppHost::_ProposeCommandlineToMonarch() - // { - // // returns true if we should create a new window - // return true; - // } } diff --git a/src/cascadia/Remoting/WindowManager.h b/src/cascadia/Remoting/WindowManager.h index 14e4fd33069..1d36ec15bf5 100644 --- a/src/cascadia/Remoting/WindowManager.h +++ b/src/cascadia/Remoting/WindowManager.h @@ -12,16 +12,21 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation WindowManager(); ~WindowManager(); - void ProposeCommandline(); + void ProposeCommandline(array_view args, const winrt::hstring cwd); bool ShouldCreateWindow(); + winrt::Microsoft::Terminal::Remoting::Peasant CurrentWindow(); + private: bool _shouldCreateWindow{ false }; DWORD _registrationHostClass{ 0 }; winrt::Microsoft::Terminal::Remoting::Monarch _monarch{ nullptr }; + winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr }; - void _RegisterAsMonarch(); - void _CreateMonarch(); + void _registerAsMonarch(); + void _createMonarch(); + bool _areWeTheKing(); + winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant(); }; } diff --git a/src/cascadia/Remoting/WindowManager.idl b/src/cascadia/Remoting/WindowManager.idl index 033602e0e37..55785aac718 100644 --- a/src/cascadia/Remoting/WindowManager.idl +++ b/src/cascadia/Remoting/WindowManager.idl @@ -1,3 +1,4 @@ +import "Peasant.idl"; namespace Microsoft.Terminal.Remoting @@ -6,7 +7,8 @@ namespace Microsoft.Terminal.Remoting [default_interface] runtimeclass WindowManager { WindowManager(); - void ProposeCommandline(); + void ProposeCommandline(String[] commands, String cwd); Boolean ShouldCreateWindow { get; }; + Peasant CurrentWindow(); }; } diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 40a3784793f..928931ada43 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -30,13 +30,35 @@ AppHost::AppHost() noexcept : { _logic = _app.Logic(); // get a ref to app's logic - _windowManager.ProposeCommandline(); - // _RegisterAsMonarch(); - // _CreateMonarch(); - _shouldCreateWindow = _windowManager.ShouldCreateWindow(); - if (!_shouldCreateWindow) { - return; + std::vector args; + if (auto commandline{ GetCommandLineW() }) + { + int argc = 0; + + // Get the argv, and turn them into a hstring array to pass to the app. + wil::unique_any argv{ CommandLineToArgvW(commandline, &argc) }; + if (argv) + { + for (auto& elem : wil::make_range(argv.get(), argc)) + { + args.emplace_back(elem); + } + } + } + if (args.empty()) + { + args.emplace_back(L"wt.exe"); + } + + _windowManager.ProposeCommandline({ args }, L"placeholder/cwd"); + // _RegisterAsMonarch(); + // _CreateMonarch(); + _shouldCreateWindow = _windowManager.ShouldCreateWindow(); + if (!_shouldCreateWindow) + { + return; + } } // If there were commandline args to our process, try and process them here.