Add manager ability to send the cmd line and working directory instead.
This commit is contained in:
parent
9dfbdec349
commit
c41151aba7
|
@ -911,12 +911,20 @@ namespace winrt::TerminalApp::implementation
|
||||||
// currently displayed, it will be shown.
|
// currently displayed, it will be shown.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - settings: the TerminalSettings object to use to create the TerminalControl with.
|
// - settings: the TerminalSettings object to use to create the TerminalControl with.
|
||||||
void App::_CreateNewTabFromSettings(GUID profileGuid, TerminalSettings settings)
|
void App::_CreateNewTabFromSettings(GUID profileGuid, TerminalSettings settings, std::optional<uint64_t> serverHandle)
|
||||||
{
|
{
|
||||||
// Initialize the new tab
|
// Initialize the new tab
|
||||||
|
|
||||||
|
TerminalConnection::ITerminalConnection connection = nullptr;
|
||||||
// Create a Conhost connection based on the values in our settings object.
|
// Create a Conhost connection based on the values in our settings object.
|
||||||
TerminalConnection::ITerminalConnection connection = TerminalConnection::ConhostConnection(settings.Commandline(), settings.StartingDirectory(), 30, 80, winrt::guid());
|
if (!serverHandle)
|
||||||
|
{
|
||||||
|
connection = TerminalConnection::ConhostConnection(settings.Commandline(), settings.StartingDirectory(), 30, 80, winrt::guid());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connection = TerminalConnection::ConhostConnection(serverHandle.value(), 30, 80, winrt::guid());
|
||||||
|
}
|
||||||
|
|
||||||
TermControl term{ settings, connection };
|
TermControl term{ settings, connection };
|
||||||
|
|
||||||
|
@ -1158,10 +1166,30 @@ namespace winrt::TerminalApp::implementation
|
||||||
return { L"Windows Terminal" };
|
return { L"Windows Terminal" };
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::IncomingConnection()
|
void App::IncomingConnection(uint64_t serverHandle)
|
||||||
{
|
{
|
||||||
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this]() {
|
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, serverHandle]() {
|
||||||
_OpenNewTab(std::nullopt);
|
// Getting Guid for default profile
|
||||||
|
const auto globalSettings = _settings->GlobalSettings();
|
||||||
|
auto profileGuid = globalSettings.GetDefaultProfile();
|
||||||
|
TerminalSettings settings = _settings->MakeSettings(profileGuid);
|
||||||
|
|
||||||
|
_CreateNewTabFromSettings(profileGuid, settings, serverHandle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::IncomingConnection(hstring cmdline, hstring workingDir)
|
||||||
|
{
|
||||||
|
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, cmdline, workingDir]() {
|
||||||
|
// Getting Guid for default profile
|
||||||
|
const auto globalSettings = _settings->GlobalSettings();
|
||||||
|
auto profileGuid = globalSettings.GetDefaultProfile();
|
||||||
|
TerminalSettings settings = _settings->MakeSettings(profileGuid);
|
||||||
|
|
||||||
|
settings.Commandline(cmdline);
|
||||||
|
settings.StartingDirectory(workingDir);
|
||||||
|
|
||||||
|
_CreateNewTabFromSettings(profileGuid, settings);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,8 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
hstring GetTitle();
|
hstring GetTitle();
|
||||||
|
|
||||||
void IncomingConnection();
|
void IncomingConnection(uint64_t serverHandle);
|
||||||
|
void IncomingConnection(hstring cmdline, hstring workingDir);
|
||||||
|
|
||||||
// -------------------------------- WinRT Events ---------------------------------
|
// -------------------------------- WinRT Events ---------------------------------
|
||||||
DECLARE_EVENT(TitleChanged, _titleChangeHandlers, winrt::Microsoft::Terminal::TerminalControl::TitleChangedEventArgs);
|
DECLARE_EVENT(TitleChanged, _titleChangeHandlers, winrt::Microsoft::Terminal::TerminalControl::TitleChangedEventArgs);
|
||||||
|
@ -102,7 +103,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
|
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
|
||||||
|
|
||||||
void _CreateNewTabFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings);
|
void _CreateNewTabFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings, std::optional<uint64_t> serverHandle = std::nullopt);
|
||||||
|
|
||||||
void _OpenNewTab(std::optional<int> profileIndex);
|
void _OpenNewTab(std::optional<int> profileIndex);
|
||||||
void _DuplicateTabViewItem();
|
void _DuplicateTabViewItem();
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace TerminalApp
|
||||||
|
|
||||||
String GetTitle();
|
String GetTitle();
|
||||||
|
|
||||||
void IncomingConnection();
|
void IncomingConnection(UInt64 serverHandle);
|
||||||
|
void IncomingConnection(String cmdline, String workingDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,23 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConhostConnection::ConhostConnection(const uint64_t server,
|
||||||
|
const uint32_t initialRows,
|
||||||
|
const uint32_t initialCols,
|
||||||
|
const guid& initialGuid) :
|
||||||
|
_initialRows{ initialRows },
|
||||||
|
_initialCols{ initialCols },
|
||||||
|
_commandline{},
|
||||||
|
_startingDirectory{},
|
||||||
|
_guid{ initialGuid },
|
||||||
|
_hServer{ reinterpret_cast<HANDLE>(server) }
|
||||||
|
{
|
||||||
|
if (_guid == guid{})
|
||||||
|
{
|
||||||
|
_guid = Utils::CreateGuid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
winrt::guid ConhostConnection::Guid() const noexcept
|
winrt::guid ConhostConnection::Guid() const noexcept
|
||||||
{
|
{
|
||||||
return _guid;
|
return _guid;
|
||||||
|
@ -71,6 +88,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||||
startingDirectory = _startingDirectory;
|
startingDirectory = _startingDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<HANDLE> server;
|
||||||
|
if (_hServer)
|
||||||
|
{
|
||||||
|
server = _hServer.get();
|
||||||
|
}
|
||||||
|
|
||||||
EnvironmentVariableMapW extraEnvVars;
|
EnvironmentVariableMapW extraEnvVars;
|
||||||
{
|
{
|
||||||
// Convert connection Guid to string and ignore the enclosing '{}'.
|
// Convert connection Guid to string and ignore the enclosing '{}'.
|
||||||
|
@ -88,6 +111,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||||
startingDirectory,
|
startingDirectory,
|
||||||
static_cast<short>(_initialCols),
|
static_cast<short>(_initialCols),
|
||||||
static_cast<short>(_initialRows),
|
static_cast<short>(_initialRows),
|
||||||
|
server,
|
||||||
&_inPipe,
|
&_inPipe,
|
||||||
&_outPipe,
|
&_outPipe,
|
||||||
&_signalPipe,
|
&_signalPipe,
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||||
struct ConhostConnection : ConhostConnectionT<ConhostConnection>
|
struct ConhostConnection : ConhostConnectionT<ConhostConnection>
|
||||||
{
|
{
|
||||||
ConhostConnection(const hstring& cmdline, const hstring& startingDirectory, const uint32_t rows, const uint32_t cols, const guid& guid);
|
ConhostConnection(const hstring& cmdline, const hstring& startingDirectory, const uint32_t rows, const uint32_t cols, const guid& guid);
|
||||||
|
ConhostConnection(const uint64_t server, const uint32_t rows, const uint32_t cols, const guid& guid);
|
||||||
|
|
||||||
winrt::event_token TerminalOutput(TerminalConnection::TerminalOutputEventArgs const& handler);
|
winrt::event_token TerminalOutput(TerminalConnection::TerminalOutputEventArgs const& handler);
|
||||||
void TerminalOutput(winrt::event_token const& token) noexcept;
|
void TerminalOutput(winrt::event_token const& token) noexcept;
|
||||||
|
@ -41,6 +42,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||||
wil::unique_handle _hOutputThread;
|
wil::unique_handle _hOutputThread;
|
||||||
wil::unique_process_information _piConhost;
|
wil::unique_process_information _piConhost;
|
||||||
wil::unique_handle _hJob;
|
wil::unique_handle _hJob;
|
||||||
|
wil::unique_handle _hServer;
|
||||||
|
|
||||||
static DWORD WINAPI StaticOutputThreadProc(LPVOID lpParameter);
|
static DWORD WINAPI StaticOutputThreadProc(LPVOID lpParameter);
|
||||||
DWORD _OutputThread();
|
DWORD _OutputThread();
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||||
runtimeclass ConhostConnection : ITerminalConnection
|
runtimeclass ConhostConnection : ITerminalConnection
|
||||||
{
|
{
|
||||||
ConhostConnection(String cmdline, String startingDirectory, UInt32 rows, UInt32 columns, Guid guid);
|
ConhostConnection(String cmdline, String startingDirectory, UInt32 rows, UInt32 columns, Guid guid);
|
||||||
|
ConhostConnection(UInt64 server, UInt32 rows, UInt32 columns, Guid guid);
|
||||||
|
|
||||||
Guid Guid { get; };
|
Guid Guid { get; };
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,9 +72,14 @@ void AppHost::Initialize()
|
||||||
_window->OnAppInitialized(_app);
|
_window->OnAppInitialized(_app);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppHost::IncomingConnection()
|
void AppHost::IncomingConnectionByHandle(HANDLE handle)
|
||||||
{
|
{
|
||||||
_app.IncomingConnection();
|
_app.IncomingConnection(reinterpret_cast<uint64_t>(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppHost::IncomingConnectionByLaunch(std::wstring_view cmdline, std::wstring_view workingDir)
|
||||||
|
{
|
||||||
|
_app.IncomingConnection(winrt::hstring(cmdline), winrt::hstring(workingDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
|
|
@ -14,7 +14,8 @@ public:
|
||||||
AppHost() noexcept;
|
AppHost() noexcept;
|
||||||
virtual ~AppHost();
|
virtual ~AppHost();
|
||||||
|
|
||||||
void IncomingConnection();
|
void IncomingConnectionByHandle(HANDLE handle);
|
||||||
|
void IncomingConnectionByLaunch(std::wstring_view cmdline, std::wstring_view workingDir);
|
||||||
void AppTitleChanged(winrt::hstring newTitle);
|
void AppTitleChanged(winrt::hstring newTitle);
|
||||||
void LastTabClosed();
|
void LastTabClosed();
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|
|
@ -108,15 +108,15 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||||
// provides an implementation of Windows.UI.Xaml.Application.
|
// provides an implementation of Windows.UI.Xaml.Application.
|
||||||
AppHost host;
|
AppHost host;
|
||||||
|
|
||||||
auto lambda = std::function<void()>([&] {
|
|
||||||
host.IncomingConnection();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a manager object for IPC.
|
// Create a manager object for IPC.
|
||||||
Manager manager;
|
Manager manager;
|
||||||
|
|
||||||
Manager::s_RegisterOnConnection(lambda);
|
// Create and register on connection callbacks from the manager into the application host.
|
||||||
|
std::function<void(HANDLE)> onHandleConnection = std::bind(&AppHost::IncomingConnectionByHandle, &host, std::placeholders::_1);
|
||||||
|
std::function<void(std::wstring_view, std::wstring_view)> onLaunchConnection = std::bind(&AppHost::IncomingConnectionByLaunch, &host, std::placeholders::_1, std::placeholders::_2);
|
||||||
|
|
||||||
|
Manager::s_RegisterOnConnection(onHandleConnection);
|
||||||
|
Manager::s_RegisterOnConnection(onLaunchConnection);
|
||||||
|
|
||||||
// !!! LOAD BEARING !!!
|
// !!! LOAD BEARING !!!
|
||||||
// This is _magic_. Do the initial loading of our settings *BEFORE* we
|
// This is _magic_. Do the initial loading of our settings *BEFORE* we
|
||||||
|
|
|
@ -104,7 +104,8 @@ ConsoleArguments::ConsoleArguments(const std::wstring& commandline,
|
||||||
_recievedEarlySizeChange{ false },
|
_recievedEarlySizeChange{ false },
|
||||||
_originalWidth{ -1 },
|
_originalWidth{ -1 },
|
||||||
_originalHeight{ -1 },
|
_originalHeight{ -1 },
|
||||||
_forceManager{ false }
|
_forceManager{ false },
|
||||||
|
_workingDirectory{ wil::GetCurrentDirectoryW().get() }
|
||||||
{
|
{
|
||||||
_clientCommandline = L"";
|
_clientCommandline = L"";
|
||||||
_vtMode = L"";
|
_vtMode = L"";
|
||||||
|
|
|
@ -111,6 +111,8 @@ private:
|
||||||
|
|
||||||
std::wstring _clientCommandline;
|
std::wstring _clientCommandline;
|
||||||
|
|
||||||
|
std::wstring _workingDirectory;
|
||||||
|
|
||||||
HANDLE _vtInHandle;
|
HANDLE _vtInHandle;
|
||||||
|
|
||||||
HANDLE _vtOutHandle;
|
HANDLE _vtOutHandle;
|
||||||
|
|
|
@ -201,6 +201,7 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||||
// - startingDirectory: The directory to start the process in
|
// - startingDirectory: The directory to start the process in
|
||||||
// - w: The initial width of the pty, in characters
|
// - w: The initial width of the pty, in characters
|
||||||
// - h: The initial height of the pty, in characters
|
// - h: The initial height of the pty, in characters
|
||||||
|
// - hServer: An optional handle to a server connection handle already established for this PTY.
|
||||||
// - hInput: A handle to the pipe for writing input to the pty.
|
// - hInput: A handle to the pipe for writing input to the pty.
|
||||||
// - hOutput: A handle to the pipe for reading the output of the pty.
|
// - hOutput: A handle to the pipe for reading the output of the pty.
|
||||||
// - hSignal: A handle to the pipe for writing signal messages to the pty.
|
// - hSignal: A handle to the pipe for writing signal messages to the pty.
|
||||||
|
@ -216,6 +217,7 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||||
std::optional<std::wstring> startingDirectory,
|
std::optional<std::wstring> startingDirectory,
|
||||||
const unsigned short w,
|
const unsigned short w,
|
||||||
const unsigned short h,
|
const unsigned short h,
|
||||||
|
std::optional<HANDLE> const hServer,
|
||||||
HANDLE* const hInput,
|
HANDLE* const hInput,
|
||||||
HANDLE* const hOutput,
|
HANDLE* const hOutput,
|
||||||
HANDLE* const hSignal,
|
HANDLE* const hSignal,
|
||||||
|
@ -254,6 +256,11 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||||
SetHandleInformation(outPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
|
SetHandleInformation(outPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
|
||||||
SetHandleInformation(signalPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
|
SetHandleInformation(signalPipeConhostSide, HANDLE_FLAG_INHERIT, 1);
|
||||||
|
|
||||||
|
if (hServer.has_value())
|
||||||
|
{
|
||||||
|
SetHandleInformation(hServer.value(), HANDLE_FLAG_INHERIT, 1);
|
||||||
|
}
|
||||||
|
|
||||||
std::wstring conhostCmdline = L"conhost.exe";
|
std::wstring conhostCmdline = L"conhost.exe";
|
||||||
conhostCmdline += L" --headless";
|
conhostCmdline += L" --headless";
|
||||||
std::wstringstream ss;
|
std::wstringstream ss;
|
||||||
|
@ -264,9 +271,19 @@ bool SignalResizeWindow(const HANDLE hSignal,
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << L" --signal 0x" << std::hex << HandleToUlong(signalPipeConhostSide);
|
ss << L" --signal 0x" << std::hex << HandleToUlong(signalPipeConhostSide);
|
||||||
|
|
||||||
|
if (hServer.has_value())
|
||||||
|
{
|
||||||
|
ss << L" --server 0x" << std::hex << HandleToUlong(hServer.value());
|
||||||
|
}
|
||||||
|
|
||||||
conhostCmdline += ss.str();
|
conhostCmdline += ss.str();
|
||||||
conhostCmdline += L" -- ";
|
|
||||||
conhostCmdline += cmdline;
|
if (!hServer.has_value())
|
||||||
|
{
|
||||||
|
conhostCmdline += L" -- ";
|
||||||
|
conhostCmdline += cmdline;
|
||||||
|
}
|
||||||
|
|
||||||
STARTUPINFO si = { 0 };
|
STARTUPINFO si = { 0 };
|
||||||
si.cb = sizeof(STARTUPINFOW);
|
si.cb = sizeof(STARTUPINFOW);
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
{
|
{
|
||||||
if (args.ShouldSendToManager())
|
if (args.ShouldSendToManager())
|
||||||
{
|
{
|
||||||
Manager::s_TrySendToManager(args.GetServerHandle());
|
if (Manager::s_TrySendToManager(args.GetServerHandle()))
|
||||||
return S_OK;
|
{
|
||||||
}
|
SleepEx(INFINITE, FALSE);
|
||||||
else
|
return S_OK;
|
||||||
{
|
}
|
||||||
return ConsoleCreateIoThreadLegacy(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ConsoleCreateIoThreadLegacy(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function has unreachable code due to its unusual lifetime. We
|
// this function has unreachable code due to its unusual lifetime. We
|
||||||
|
@ -32,6 +33,15 @@
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForCmdLine(ConsoleArguments& args)
|
[[nodiscard]] HRESULT Entrypoints::StartConsoleForCmdLine(ConsoleArguments& args)
|
||||||
{
|
{
|
||||||
|
if (args.ShouldSendToManager())
|
||||||
|
{
|
||||||
|
if (Manager::s_TrySendToManager(args.GetClientCommandline(), L"C:\\windows\\system32"))
|
||||||
|
{
|
||||||
|
SleepEx(INFINITE, FALSE);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a scope because we're going to exit thread if everything goes well.
|
// Create a scope because we're going to exit thread if everything goes well.
|
||||||
// This scope will ensure all C++ objects and smart pointers get a chance to destruct before ExitThread is called.
|
// This scope will ensure all C++ objects and smart pointers get a chance to destruct before ExitThread is called.
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,6 +39,7 @@ Manager::Manager() :
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ManagerMessageQuery query;
|
ManagerMessageQuery query;
|
||||||
|
query.size = sizeof(query);
|
||||||
query.type = ManagerMessageTypes::GetManagerPid;
|
query.type = ManagerMessageTypes::GetManagerPid;
|
||||||
|
|
||||||
const auto reply = _ask(query);
|
const auto reply = _ask(query);
|
||||||
|
@ -50,7 +51,7 @@ Manager::Manager() :
|
||||||
|
|
||||||
WaitForSingleObject(managerProcess.get(), INFINITE);
|
WaitForSingleObject(managerProcess.get(), INFINITE);
|
||||||
_becomeServer();
|
_becomeServer();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ bool Manager::s_TrySendToManager(const HANDLE server)
|
||||||
{
|
{
|
||||||
// Get PID from remote process.
|
// Get PID from remote process.
|
||||||
ManagerMessageQuery query;
|
ManagerMessageQuery query;
|
||||||
|
query.size = sizeof(query);
|
||||||
query.type = ManagerMessageTypes::GetManagerPid;
|
query.type = ManagerMessageTypes::GetManagerPid;
|
||||||
|
|
||||||
auto reply = _ask(query);
|
auto reply = _ask(query);
|
||||||
|
@ -88,12 +90,51 @@ bool Manager::s_TrySendToManager(const HANDLE server)
|
||||||
DUPLICATE_SAME_ACCESS));
|
DUPLICATE_SAME_ACCESS));
|
||||||
|
|
||||||
// Tell remote process about new handle ID
|
// Tell remote process about new handle ID
|
||||||
|
query.size = sizeof(query);
|
||||||
query.type = ManagerMessageTypes::SendConnection;
|
query.type = ManagerMessageTypes::SendConnection;
|
||||||
query.query.sendConn.handle = targetHandle;
|
query.query.sendConn.handle = targetHandle;
|
||||||
|
|
||||||
reply = _ask(query);
|
reply = _ask(query);
|
||||||
|
|
||||||
return true;
|
return reply.reply.sendConn.ok;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_CAUGHT_EXCEPTION();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Manager::s_TrySendToManager(const std::wstring_view cmdline,
|
||||||
|
const std::wstring_view workingDir)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Figure out how much data we actually need to send with the variable length strings
|
||||||
|
size_t size = sizeof(ManagerMessageQuery) + 1;
|
||||||
|
size += 2*(cmdline.size() + 1);
|
||||||
|
size += 2*(workingDir.size() + 1);
|
||||||
|
|
||||||
|
// Make a big buffer to hold it all contiguously
|
||||||
|
const auto buffer = std::make_unique<byte[]>(size);
|
||||||
|
|
||||||
|
// Make pointers to fill up each piece of data
|
||||||
|
const auto query = reinterpret_cast<ManagerMessageQuery*>(buffer.get());
|
||||||
|
const auto cmdPayload = reinterpret_cast<PWCHAR>(buffer.get() + sizeof(ManagerMessageQuery) + 1);
|
||||||
|
const auto workingPayload = reinterpret_cast<PWCHAR>(buffer.get() + sizeof(ManagerMessageQuery) + 1 + (cmdline.size() + 1) * 2);
|
||||||
|
|
||||||
|
// Tell the remote process the command line and working directory
|
||||||
|
query->size = gsl::narrow<DWORD>(size);
|
||||||
|
query->type = ManagerMessageTypes::SendCmdAndWorking;
|
||||||
|
query->query.sendCmdAndWorking.cmd = gsl::narrow<DWORD>(cmdline.size());
|
||||||
|
query->query.sendCmdAndWorking.working = gsl::narrow<DWORD>(workingDir.size());
|
||||||
|
|
||||||
|
THROW_IF_FAILED(StringCchCopyW(cmdPayload, cmdline.size() + 1, cmdline.data()));
|
||||||
|
THROW_IF_FAILED(StringCchCopyW(workingPayload, workingDir.size() + 1, workingDir.data()));
|
||||||
|
|
||||||
|
const auto reply = _ask(*query);
|
||||||
|
|
||||||
|
return reply.reply.sendConn.ok;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -163,7 +204,7 @@ void Manager::_serverLoop()
|
||||||
const auto loosePipeHandle = pipe.release();
|
const auto loosePipeHandle = pipe.release();
|
||||||
auto future = std::async(std::launch::async, [this, loosePipeHandle] {
|
auto future = std::async(std::launch::async, [this, loosePipeHandle] {
|
||||||
_perClientLoop(wil::unique_handle(loosePipeHandle));
|
_perClientLoop(wil::unique_handle(loosePipeHandle));
|
||||||
});
|
});
|
||||||
_perClientWork.push_back(std::move(future));
|
_perClientWork.push_back(std::move(future));
|
||||||
}
|
}
|
||||||
else if (ret == WAIT_FAILED)
|
else if (ret == WAIT_FAILED)
|
||||||
|
@ -184,11 +225,30 @@ void Manager::_perClientLoop(wil::unique_handle pipe)
|
||||||
{
|
{
|
||||||
ManagerMessageQuery query;
|
ManagerMessageQuery query;
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
THROW_IF_WIN32_BOOL_FALSE(ReadFile(pipe.get(),
|
SetLastError(S_OK);
|
||||||
&query,
|
const auto result = ReadFile(pipe.get(),
|
||||||
sizeof(query),
|
&query,
|
||||||
&bytesRead,
|
sizeof(query),
|
||||||
nullptr));
|
&bytesRead,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
// False is OK if it's ERROR_MORE_DATA.
|
||||||
|
const auto gle = GetLastError();
|
||||||
|
THROW_LAST_ERROR_IF(!result && gle != ERROR_MORE_DATA);
|
||||||
|
|
||||||
|
std::unique_ptr<byte[]> buffer;
|
||||||
|
if (gle == ERROR_MORE_DATA)
|
||||||
|
{
|
||||||
|
const auto remainingBytes = query.size - gsl::narrow<DWORD>(sizeof(query));
|
||||||
|
buffer = std::make_unique<byte[]>(remainingBytes);
|
||||||
|
|
||||||
|
bytesRead = 0;
|
||||||
|
THROW_IF_WIN32_BOOL_FALSE(ReadFile(pipe.get(),
|
||||||
|
buffer.get(),
|
||||||
|
remainingBytes,
|
||||||
|
&bytesRead,
|
||||||
|
nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
ManagerMessageReply reply;
|
ManagerMessageReply reply;
|
||||||
switch (query.type)
|
switch (query.type)
|
||||||
|
@ -199,6 +259,9 @@ void Manager::_perClientLoop(wil::unique_handle pipe)
|
||||||
case ManagerMessageTypes::SendConnection:
|
case ManagerMessageTypes::SendConnection:
|
||||||
reply = _sendConnection(query);
|
reply = _sendConnection(query);
|
||||||
break;
|
break;
|
||||||
|
case ManagerMessageTypes::SendCmdAndWorking:
|
||||||
|
reply = _sendCmdAndWorking(query, buffer);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
THROW_HR(E_NOTIMPL);
|
THROW_HR(E_NOTIMPL);
|
||||||
}
|
}
|
||||||
|
@ -212,14 +275,14 @@ void Manager::_perClientLoop(wil::unique_handle pipe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::ManagerMessageReply Manager::_ask(Manager::ManagerMessageQuery query)
|
Manager::ManagerMessageReply Manager::_ask(Manager::ManagerMessageQuery& query)
|
||||||
{
|
{
|
||||||
ManagerMessageReply reply;
|
ManagerMessageReply reply;
|
||||||
|
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
THROW_IF_WIN32_BOOL_FALSE(CallNamedPipeW(PIPE_NAME.data(),
|
THROW_IF_WIN32_BOOL_FALSE(CallNamedPipeW(PIPE_NAME.data(),
|
||||||
&query,
|
&query,
|
||||||
sizeof(query),
|
query.size,
|
||||||
&reply,
|
&reply,
|
||||||
sizeof(reply),
|
sizeof(reply),
|
||||||
&bytesRead,
|
&bytesRead,
|
||||||
|
@ -238,17 +301,21 @@ Manager::ManagerMessageReply Manager::_getPid(ManagerMessageQuery /*query*/)
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::function<void()>> s_onConnection;
|
static std::vector<std::function<void(HANDLE)>> s_onHandleConnection;
|
||||||
|
|
||||||
|
void Manager::s_RegisterOnConnection(std::function<void(HANDLE)> func)
|
||||||
|
{
|
||||||
|
s_onHandleConnection.push_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
Manager::ManagerMessageReply Manager::_sendConnection(ManagerMessageQuery query)
|
Manager::ManagerMessageReply Manager::_sendConnection(ManagerMessageQuery query)
|
||||||
{
|
{
|
||||||
const auto server = query.query.sendConn.handle;
|
const auto serverHandle = query.query.sendConn.handle;
|
||||||
server;
|
|
||||||
|
|
||||||
// create new conhost connection...
|
// create new conhost connection...
|
||||||
for (const auto& func : s_onConnection)
|
for (const auto& func : s_onHandleConnection)
|
||||||
{
|
{
|
||||||
func();
|
func(serverHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagerMessageReply reply;
|
ManagerMessageReply reply;
|
||||||
|
@ -259,8 +326,32 @@ Manager::ManagerMessageReply Manager::_sendConnection(ManagerMessageQuery query)
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::s_RegisterOnConnection(std::function<void()> func)
|
static std::vector<std::function<void(std::wstring_view, std::wstring_view)>> s_onLaunchConnection;
|
||||||
|
|
||||||
|
void Manager::s_RegisterOnConnection(std::function<void(std::wstring_view, std::wstring_view)> func)
|
||||||
{
|
{
|
||||||
s_onConnection.push_back(func);
|
s_onLaunchConnection.push_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager::ManagerMessageReply Manager::_sendCmdAndWorking(ManagerMessageQuery query, std::unique_ptr<BYTE[]>& buffer)
|
||||||
|
{
|
||||||
|
const auto cmd = query.query.sendCmdAndWorking.cmd;
|
||||||
|
const auto work = query.query.sendCmdAndWorking.working;
|
||||||
|
|
||||||
|
std::wstring_view cmdline(reinterpret_cast<wchar_t*>(buffer.get() + 1), cmd);
|
||||||
|
std::wstring_view workingDir(reinterpret_cast<wchar_t*>(buffer.get() + 1 + (cmd + 1) * 2), work);
|
||||||
|
|
||||||
|
// create new conhost connection...
|
||||||
|
for (const auto& func : s_onLaunchConnection)
|
||||||
|
{
|
||||||
|
func(cmdline, workingDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagerMessageReply reply;
|
||||||
|
|
||||||
|
reply.type = ManagerMessageTypes::SendCmdAndWorking;
|
||||||
|
reply.reply.sendCmdAndWorking.ok = true;
|
||||||
|
|
||||||
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,11 @@ public:
|
||||||
|
|
||||||
void NotifyExit();
|
void NotifyExit();
|
||||||
|
|
||||||
static void s_RegisterOnConnection(std::function<void()> func);
|
static void s_RegisterOnConnection(std::function<void(HANDLE)> func);
|
||||||
|
static void s_RegisterOnConnection(std::function<void(std::wstring_view, std::wstring_view)> func);
|
||||||
static bool s_TrySendToManager(const HANDLE server);
|
static bool s_TrySendToManager(const HANDLE server);
|
||||||
|
static bool s_TrySendToManager(const std::wstring_view cmdline,
|
||||||
|
const std::wstring_view workingDir);
|
||||||
|
|
||||||
Manager(const Manager&) = delete;
|
Manager(const Manager&) = delete;
|
||||||
Manager(Manager&&) = delete;
|
Manager(Manager&&) = delete;
|
||||||
|
@ -28,11 +31,13 @@ private:
|
||||||
enum class ManagerMessageTypes
|
enum class ManagerMessageTypes
|
||||||
{
|
{
|
||||||
GetManagerPid,
|
GetManagerPid,
|
||||||
SendConnection
|
SendConnection,
|
||||||
|
SendCmdAndWorking
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ManagerMessageQuery
|
struct ManagerMessageQuery
|
||||||
{
|
{
|
||||||
|
DWORD size;
|
||||||
ManagerMessageTypes type;
|
ManagerMessageTypes type;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -40,6 +45,11 @@ private:
|
||||||
{
|
{
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
} sendConn;
|
} sendConn;
|
||||||
|
struct SendCmdAndWorking
|
||||||
|
{
|
||||||
|
DWORD cmd;
|
||||||
|
DWORD working;
|
||||||
|
} sendCmdAndWorking;
|
||||||
} query;
|
} query;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,12 +66,17 @@ private:
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
} sendConn;
|
} sendConn;
|
||||||
|
struct SendCmdAndWorking
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
} sendCmdAndWorking;
|
||||||
} reply;
|
} reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ManagerMessageReply _ask(ManagerMessageQuery query);
|
static ManagerMessageReply _ask(ManagerMessageQuery& query);
|
||||||
static ManagerMessageReply _getPid(ManagerMessageQuery query);
|
static ManagerMessageReply _getPid(ManagerMessageQuery query);
|
||||||
static ManagerMessageReply _sendConnection(ManagerMessageQuery query);
|
static ManagerMessageReply _sendConnection(ManagerMessageQuery query);
|
||||||
|
static ManagerMessageReply _sendCmdAndWorking(ManagerMessageQuery query, std::unique_ptr<byte[]>& buffer);
|
||||||
|
|
||||||
void _becomeServer();
|
void _becomeServer();
|
||||||
void _serverLoop();
|
void _serverLoop();
|
||||||
|
|
Loading…
Reference in a new issue