mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-17 19:51:06 +00:00
Compare commits
4 Commits
dev/lhecke
...
dev/miniks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c41151aba7 | ||
|
|
9dfbdec349 | ||
|
|
9e8f891460 | ||
|
|
0bf347f428 |
@@ -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,6 +1166,33 @@ namespace winrt::TerminalApp::implementation
|
|||||||
return { L"Windows Terminal" };
|
return { L"Windows Terminal" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::IncomingConnection(uint64_t serverHandle)
|
||||||
|
{
|
||||||
|
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, serverHandle]() {
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Additional responses to clicking on a TabView's item. Currently, just remove tab with middle click
|
// - Additional responses to clicking on a TabView's item. Currently, just remove tab with middle click
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ namespace winrt::TerminalApp::implementation
|
|||||||
|
|
||||||
hstring GetTitle();
|
hstring GetTitle();
|
||||||
|
|
||||||
|
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);
|
||||||
DECLARE_EVENT(LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
|
DECLARE_EVENT(LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
|
||||||
@@ -100,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();
|
||||||
|
|||||||
@@ -30,5 +30,8 @@ namespace TerminalApp
|
|||||||
event LastTabClosedEventArgs LastTabClosed;
|
event LastTabClosedEventArgs LastTabClosed;
|
||||||
|
|
||||||
String GetTitle();
|
String GetTitle();
|
||||||
|
|
||||||
|
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,6 +72,16 @@ void AppHost::Initialize()
|
|||||||
_window->OnAppInitialized(_app);
|
_window->OnAppInitialized(_app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppHost::IncomingConnectionByHandle(HANDLE handle)
|
||||||
|
{
|
||||||
|
_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:
|
||||||
// - Called when the app's title changes. Fires off a window message so we can
|
// - Called when the app's title changes. Fires off a window message so we can
|
||||||
// update the window's title on the main thread.
|
// update the window's title on the main thread.
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ public:
|
|||||||
AppHost() noexcept;
|
AppHost() noexcept;
|
||||||
virtual ~AppHost();
|
virtual ~AppHost();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ void IslandWindow::Close()
|
|||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Set a callback to be called when we process a WM_CREATE message. This gives
|
// - Set a callback to be called when we process a WM_CREATE message. This gives
|
||||||
// the AppHost a chance to resize the window to the propoer size.
|
// the AppHost a chance to resize the window to the proper size.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - pfn: a function to be called during the handling of WM_CREATE. It takes two
|
// - pfn: a function to be called during the handling of WM_CREATE. It takes two
|
||||||
// parameters:
|
// parameters:
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||||
|
|
||||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@@ -79,13 +77,11 @@
|
|||||||
<DeploymentContent>true</DeploymentContent>
|
<DeploymentContent>true</DeploymentContent>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</NativeReferenceFile>
|
</NativeReferenceFile>
|
||||||
|
|
||||||
<!-- Manually include the xbf files from the app project as content files -->
|
<!-- Manually include the xbf files from the app project as content files -->
|
||||||
<NativeReferenceFile Include="$(OpenConsoleDir)$(Platform)\$(Configuration)\TerminalAppLib\*.xbf">
|
<NativeReferenceFile Include="$(OpenConsoleDir)$(Platform)\$(Configuration)\TerminalAppLib\*.xbf">
|
||||||
<DeploymentContent>true</DeploymentContent>
|
<DeploymentContent>true</DeploymentContent>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</NativeReferenceFile>
|
</NativeReferenceFile>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
the packaging project wont recurse through our dependencies, you have to
|
the packaging project wont recurse through our dependencies, you have to
|
||||||
make sure that if you add a cppwinrt dependency to any of these projects,
|
make sure that if you add a cppwinrt dependency to any of these projects,
|
||||||
@@ -100,15 +96,12 @@
|
|||||||
manually add a reference to the TerminalApp winmd and dll below, because we
|
manually add a reference to the TerminalApp winmd and dll below, because we
|
||||||
still need those. -->
|
still need those. -->
|
||||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- A small helper for paths to the compiled cppwinrt projects -->
|
<!-- A small helper for paths to the compiled cppwinrt projects -->
|
||||||
<_BinRoot Condition="'$(Platform)' != 'Win32'">$(OpenConsoleDir)$(Platform)\$(Configuration)\</_BinRoot>
|
<_BinRoot Condition="'$(Platform)' != 'Win32'">$(OpenConsoleDir)$(Platform)\$(Configuration)\</_BinRoot>
|
||||||
<_BinRoot Condition="'$(Platform)' == 'Win32'">$(OpenConsoleDir)$(Configuration)\</_BinRoot>
|
<_BinRoot Condition="'$(Platform)' == 'Win32'">$(OpenConsoleDir)$(Configuration)\</_BinRoot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- Manually reference TerminalApp, since we can't use a ProjectReference. -->
|
<!-- Manually reference TerminalApp, since we can't use a ProjectReference. -->
|
||||||
<Reference Include="TerminalApp">
|
<Reference Include="TerminalApp">
|
||||||
@@ -118,9 +111,7 @@
|
|||||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||||
</Reference>
|
</Reference>
|
||||||
<ReferenceCopyLocalPaths Include="$(_BinRoot)\TerminalApp\TerminalApp.dll" />
|
<ReferenceCopyLocalPaths Include="$(_BinRoot)\TerminalApp\TerminalApp.dll" />
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This ItemGroup and the Globals PropertyGroup below it are required in order
|
This ItemGroup and the Globals PropertyGroup below it are required in order
|
||||||
to enable F5 debugging for the unpackaged application
|
to enable F5 debugging for the unpackaged application
|
||||||
@@ -136,7 +127,6 @@
|
|||||||
<!-- DON'T REDIRECT OUR OUTPUT -->
|
<!-- DON'T REDIRECT OUR OUTPUT -->
|
||||||
<NoOutputRedirection>true</NoOutputRedirection>
|
<NoOutputRedirection>true</NoOutputRedirection>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets')" />
|
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets')" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -148,11 +138,9 @@
|
|||||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||||
|
|
||||||
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190521.3\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190521.3\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190521.3\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190521.3\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||||
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets')" />
|
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.0-rc\build\native\Microsoft.VCRTForwarders.140.targets')" />
|
||||||
</Project>
|
</Project>
|
||||||
30
src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj.filters
Normal file
30
src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj.filters
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Manifest Include="WindowsTerminal.manifest" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="pch.cpp" />
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="AppHost.cpp" />
|
||||||
|
<ClCompile Include="IslandWindow.cpp" />
|
||||||
|
<ClCompile Include="NonClientIslandWindow.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="AppHost.h" />
|
||||||
|
<ClInclude Include="BaseWindow.h" />
|
||||||
|
<ClInclude Include="IslandWindow.h" />
|
||||||
|
<ClInclude Include="NonClientIslandWindow.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="WindowsTerminal.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "AppHost.h"
|
#include "AppHost.h"
|
||||||
|
#include "..\..\types\Manager.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
|
||||||
using namespace winrt;
|
using namespace winrt;
|
||||||
@@ -107,6 +108,16 @@ 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;
|
||||||
|
|
||||||
|
// Create a manager object for IPC.
|
||||||
|
Manager manager;
|
||||||
|
|
||||||
|
// 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
|
||||||
// initialize our COM apartment type. This is because the Windows.Storage
|
// initialize our COM apartment type. This is because the Windows.Storage
|
||||||
@@ -132,5 +143,8 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
|||||||
TranslateMessage(&message);
|
TranslateMessage(&message);
|
||||||
DispatchMessage(&message);
|
DispatchMessage(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
manager.NotifyExit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const std::wstring_view ConsoleArguments::HEIGHT_ARG = L"--height";
|
|||||||
const std::wstring_view ConsoleArguments::INHERIT_CURSOR_ARG = L"--inheritcursor";
|
const std::wstring_view ConsoleArguments::INHERIT_CURSOR_ARG = L"--inheritcursor";
|
||||||
const std::wstring_view ConsoleArguments::FEATURE_ARG = L"--feature";
|
const std::wstring_view ConsoleArguments::FEATURE_ARG = L"--feature";
|
||||||
const std::wstring_view ConsoleArguments::FEATURE_PTY_ARG = L"pty";
|
const std::wstring_view ConsoleArguments::FEATURE_PTY_ARG = L"pty";
|
||||||
|
const std::wstring_view ConsoleArguments::FORCE_MANAGER_ARG = L"--manager";
|
||||||
|
|
||||||
std::wstring EscapeArgument(std::wstring_view ac)
|
std::wstring EscapeArgument(std::wstring_view ac)
|
||||||
{
|
{
|
||||||
@@ -102,7 +103,9 @@ ConsoleArguments::ConsoleArguments(const std::wstring& commandline,
|
|||||||
_vtOutHandle(hStdOut),
|
_vtOutHandle(hStdOut),
|
||||||
_recievedEarlySizeChange{ false },
|
_recievedEarlySizeChange{ false },
|
||||||
_originalWidth{ -1 },
|
_originalWidth{ -1 },
|
||||||
_originalHeight{ -1 }
|
_originalHeight{ -1 },
|
||||||
|
_forceManager{ false },
|
||||||
|
_workingDirectory{ wil::GetCurrentDirectoryW().get() }
|
||||||
{
|
{
|
||||||
_clientCommandline = L"";
|
_clientCommandline = L"";
|
||||||
_vtMode = L"";
|
_vtMode = L"";
|
||||||
@@ -285,7 +288,7 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
|||||||
// - S_OK if we could successfully parse the given text and store it in the handle value location.
|
// - S_OK if we could successfully parse the given text and store it in the handle value location.
|
||||||
// - E_INVALIDARG if we couldn't parse the text as a valid hex-encoded handle number OR
|
// - E_INVALIDARG if we couldn't parse the text as a valid hex-encoded handle number OR
|
||||||
// if the handle value was already filled.
|
// if the handle value was already filled.
|
||||||
[[nodiscard]] HRESULT ConsoleArguments::s_ParseHandleArg(const std::wstring& handleAsText, _Inout_ DWORD& handleAsVal)
|
[[nodiscard]] HRESULT ConsoleArguments::s_ParseHandleArg(const std::wstring& handleAsText, _Inout_ HANDLE& handleAsVal)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
@@ -296,13 +299,15 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
|||||||
}
|
}
|
||||||
else if (0 == handleAsVal)
|
else if (0 == handleAsVal)
|
||||||
{
|
{
|
||||||
handleAsVal = wcstoul(handleAsText.c_str(), nullptr /*endptr*/, 16 /*base*/);
|
const auto handleAsUlong = wcstoul(handleAsText.c_str(), nullptr /*endptr*/, 16 /*base*/);
|
||||||
|
|
||||||
// If the handle didn't parse into a reasonable handle ID, invalid.
|
// If the handle didn't parse into a reasonable handle ID, invalid.
|
||||||
if (handleAsVal == 0)
|
if (handleAsUlong == 0)
|
||||||
{
|
{
|
||||||
hr = E_INVALIDARG;
|
hr = E_INVALIDARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAsVal = UlongToHandle(handleAsUlong);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -467,6 +472,12 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
|
|||||||
{
|
{
|
||||||
hr = s_HandleFeatureValue(args, i);
|
hr = s_HandleFeatureValue(args, i);
|
||||||
}
|
}
|
||||||
|
else if (arg == FORCE_MANAGER_ARG)
|
||||||
|
{
|
||||||
|
_forceManager = true;
|
||||||
|
s_ConsumeArg(args, i);
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
else if (arg == HEADLESS_ARG)
|
else if (arg == HEADLESS_ARG)
|
||||||
{
|
{
|
||||||
_headless = true;
|
_headless = true;
|
||||||
@@ -552,62 +563,72 @@ bool ConsoleArguments::InConptyMode() const noexcept
|
|||||||
return IsValidHandle(_vtInHandle) || IsValidHandle(_vtOutHandle) || HasSignalHandle();
|
return IsValidHandle(_vtInHandle) || IsValidHandle(_vtOutHandle) || HasSignalHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleArguments::IsHeadless() const
|
bool ConsoleArguments::IsHeadless() const noexcept
|
||||||
{
|
{
|
||||||
return _headless;
|
return _headless;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleArguments::ShouldCreateServerHandle() const
|
bool ConsoleArguments::ShouldCreateServerHandle() const noexcept
|
||||||
{
|
{
|
||||||
return _createServerHandle;
|
return _createServerHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE ConsoleArguments::GetServerHandle() const
|
bool ConsoleArguments::ShouldSendToManager() const noexcept
|
||||||
{
|
{
|
||||||
return ULongToHandle(_serverHandle);
|
return _forceManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE ConsoleArguments::GetSignalHandle() const
|
HANDLE ConsoleArguments::GetServerHandle() const noexcept
|
||||||
{
|
{
|
||||||
return ULongToHandle(_signalHandle);
|
return _serverHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE ConsoleArguments::GetVtInHandle() const
|
void ConsoleArguments::SetServerHandle(const HANDLE server) noexcept
|
||||||
|
{
|
||||||
|
_serverHandle = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE ConsoleArguments::GetSignalHandle() const noexcept
|
||||||
|
{
|
||||||
|
return _signalHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE ConsoleArguments::GetVtInHandle() const noexcept
|
||||||
{
|
{
|
||||||
return _vtInHandle;
|
return _vtInHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE ConsoleArguments::GetVtOutHandle() const
|
HANDLE ConsoleArguments::GetVtOutHandle() const noexcept
|
||||||
{
|
{
|
||||||
return _vtOutHandle;
|
return _vtOutHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring ConsoleArguments::GetClientCommandline() const
|
std::wstring_view ConsoleArguments::GetClientCommandline() const noexcept
|
||||||
{
|
{
|
||||||
return _clientCommandline;
|
return _clientCommandline;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring ConsoleArguments::GetVtMode() const
|
std::wstring ConsoleArguments::GetVtMode() const noexcept
|
||||||
{
|
{
|
||||||
return _vtMode;
|
return _vtMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleArguments::GetForceV1() const
|
bool ConsoleArguments::GetForceV1() const noexcept
|
||||||
{
|
{
|
||||||
return _forceV1;
|
return _forceV1;
|
||||||
}
|
}
|
||||||
|
|
||||||
short ConsoleArguments::GetWidth() const
|
short ConsoleArguments::GetWidth() const noexcept
|
||||||
{
|
{
|
||||||
return _width;
|
return _width;
|
||||||
}
|
}
|
||||||
|
|
||||||
short ConsoleArguments::GetHeight() const
|
short ConsoleArguments::GetHeight() const noexcept
|
||||||
{
|
{
|
||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleArguments::GetInheritCursor() const
|
bool ConsoleArguments::GetInheritCursor() const noexcept
|
||||||
{
|
{
|
||||||
return _inheritCursor;
|
return _inheritCursor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,23 +33,26 @@ public:
|
|||||||
|
|
||||||
bool HasVtHandles() const;
|
bool HasVtHandles() const;
|
||||||
bool InConptyMode() const noexcept;
|
bool InConptyMode() const noexcept;
|
||||||
bool IsHeadless() const;
|
bool IsHeadless() const noexcept;
|
||||||
bool ShouldCreateServerHandle() const;
|
bool ShouldCreateServerHandle() const noexcept;
|
||||||
|
bool ShouldSendToManager() const noexcept;
|
||||||
|
|
||||||
HANDLE GetServerHandle() const;
|
HANDLE GetServerHandle() const noexcept;
|
||||||
HANDLE GetVtInHandle() const;
|
void SetServerHandle(const HANDLE server) noexcept;
|
||||||
HANDLE GetVtOutHandle() const;
|
|
||||||
|
HANDLE GetVtInHandle() const noexcept;
|
||||||
|
HANDLE GetVtOutHandle() const noexcept;
|
||||||
|
|
||||||
bool HasSignalHandle() const;
|
bool HasSignalHandle() const;
|
||||||
HANDLE GetSignalHandle() const;
|
HANDLE GetSignalHandle() const noexcept;
|
||||||
|
|
||||||
std::wstring GetClientCommandline() const;
|
std::wstring_view GetClientCommandline() const noexcept;
|
||||||
std::wstring GetVtMode() const;
|
std::wstring GetVtMode() const noexcept;
|
||||||
bool GetForceV1() const;
|
bool GetForceV1() const noexcept;
|
||||||
|
|
||||||
short GetWidth() const;
|
short GetWidth() const noexcept;
|
||||||
short GetHeight() const;
|
short GetHeight() const noexcept;
|
||||||
bool GetInheritCursor() const;
|
bool GetInheritCursor() const noexcept;
|
||||||
|
|
||||||
void SetExpectedSize(COORD dimensions) noexcept;
|
void SetExpectedSize(COORD dimensions) noexcept;
|
||||||
|
|
||||||
@@ -66,6 +69,7 @@ public:
|
|||||||
static const std::wstring_view INHERIT_CURSOR_ARG;
|
static const std::wstring_view INHERIT_CURSOR_ARG;
|
||||||
static const std::wstring_view FEATURE_ARG;
|
static const std::wstring_view FEATURE_ARG;
|
||||||
static const std::wstring_view FEATURE_PTY_ARG;
|
static const std::wstring_view FEATURE_PTY_ARG;
|
||||||
|
static const std::wstring_view FORCE_MANAGER_ARG;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef UNIT_TESTING
|
#ifdef UNIT_TESTING
|
||||||
@@ -107,6 +111,8 @@ private:
|
|||||||
|
|
||||||
std::wstring _clientCommandline;
|
std::wstring _clientCommandline;
|
||||||
|
|
||||||
|
std::wstring _workingDirectory;
|
||||||
|
|
||||||
HANDLE _vtInHandle;
|
HANDLE _vtInHandle;
|
||||||
|
|
||||||
HANDLE _vtOutHandle;
|
HANDLE _vtOutHandle;
|
||||||
@@ -119,9 +125,10 @@ private:
|
|||||||
short _width;
|
short _width;
|
||||||
short _height;
|
short _height;
|
||||||
|
|
||||||
|
bool _forceManager;
|
||||||
bool _createServerHandle;
|
bool _createServerHandle;
|
||||||
DWORD _serverHandle;
|
HANDLE _serverHandle;
|
||||||
DWORD _signalHandle;
|
HANDLE _signalHandle;
|
||||||
bool _inheritCursor;
|
bool _inheritCursor;
|
||||||
|
|
||||||
bool _recievedEarlySizeChange;
|
bool _recievedEarlySizeChange;
|
||||||
@@ -144,7 +151,7 @@ private:
|
|||||||
_Inout_ size_t& index);
|
_Inout_ size_t& index);
|
||||||
|
|
||||||
[[nodiscard]] static HRESULT s_ParseHandleArg(const std::wstring& handleAsText,
|
[[nodiscard]] static HRESULT s_ParseHandleArg(const std::wstring& handleAsText,
|
||||||
_Inout_ DWORD& handleAsVal);
|
_Inout_ HANDLE& handle);
|
||||||
|
|
||||||
#ifdef UNIT_TESTING
|
#ifdef UNIT_TESTING
|
||||||
friend class ConsoleArgumentsTests;
|
friend class ConsoleArgumentsTests;
|
||||||
|
|||||||
@@ -70,14 +70,14 @@ VtIo::VtIo() :
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] HRESULT VtIo::Initialize(const ConsoleArguments* const pArgs)
|
[[nodiscard]] HRESULT VtIo::Initialize(const ConsoleArguments args)
|
||||||
{
|
{
|
||||||
_lookingForCursorPosition = pArgs->GetInheritCursor();
|
_lookingForCursorPosition = args.GetInheritCursor();
|
||||||
|
|
||||||
// If we were already given VT handles, set up the VT IO engine to use those.
|
// If we were already given VT handles, set up the VT IO engine to use those.
|
||||||
if (pArgs->InConptyMode())
|
if (args.InConptyMode())
|
||||||
{
|
{
|
||||||
return _Initialize(pArgs->GetVtInHandle(), pArgs->GetVtOutHandle(), pArgs->GetVtMode(), pArgs->GetSignalHandle());
|
return _Initialize(args.GetVtInHandle(), args.GetVtOutHandle(), args.GetVtMode(), args.GetSignalHandle());
|
||||||
}
|
}
|
||||||
// Didn't need to initialize if we didn't have VT stuff. It's still OK, but report we did nothing.
|
// Didn't need to initialize if we didn't have VT stuff. It's still OK, but report we did nothing.
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
VtIo();
|
VtIo();
|
||||||
virtual ~VtIo() override = default;
|
virtual ~VtIo() override = default;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Initialize(const ConsoleArguments* const pArgs);
|
[[nodiscard]] HRESULT Initialize(const ConsoleArguments args);
|
||||||
|
|
||||||
[[nodiscard]] HRESULT CreateAndStartSignalThread() noexcept;
|
[[nodiscard]] HRESULT CreateAndStartSignalThread() noexcept;
|
||||||
[[nodiscard]] HRESULT CreateIoHandlers() noexcept;
|
[[nodiscard]] HRESULT CreateIoHandlers() noexcept;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "srvinit.h"
|
#include "srvinit.h"
|
||||||
#include "..\server\Entrypoints.h"
|
#include "..\server\Entrypoints.h"
|
||||||
#include "..\interactivity\inc\ServiceLocator.hpp"
|
#include "..\interactivity\inc\ServiceLocator.hpp"
|
||||||
|
#include "..\types\Manager.h"
|
||||||
|
|
||||||
// Define TraceLogging provider
|
// Define TraceLogging provider
|
||||||
TRACELOGGING_DEFINE_PROVIDER(
|
TRACELOGGING_DEFINE_PROVIDER(
|
||||||
@@ -195,7 +196,7 @@ int CALLBACK wWinMain(
|
|||||||
{
|
{
|
||||||
if (args.ShouldCreateServerHandle())
|
if (args.ShouldCreateServerHandle())
|
||||||
{
|
{
|
||||||
hr = Entrypoints::StartConsoleForCmdLine(args.GetClientCommandline().c_str(), &args);
|
hr = Entrypoints::StartConsoleForCmdLine(args);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -203,7 +204,7 @@ int CALLBACK wWinMain(
|
|||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
hr = Entrypoints::StartConsoleForServerHandle(args.GetServerHandle(), &args);
|
hr = Entrypoints::StartConsoleForServerHandle(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "renderFontDefaults.hpp"
|
#include "renderFontDefaults.hpp"
|
||||||
|
|
||||||
#include "ApiRoutines.h"
|
#include "ApiRoutines.h"
|
||||||
|
#include "ConsoleArguments.hpp"
|
||||||
|
|
||||||
#include "../types/inc/GlyphWidth.hpp"
|
#include "../types/inc/GlyphWidth.hpp"
|
||||||
|
|
||||||
@@ -31,15 +32,15 @@ using namespace Microsoft::Console::Render;
|
|||||||
const UINT CONSOLE_EVENT_FAILURE_ID = 21790;
|
const UINT CONSOLE_EVENT_FAILURE_ID = 21790;
|
||||||
const UINT CONSOLE_LPC_PORT_FAILURE_ID = 21791;
|
const UINT CONSOLE_LPC_PORT_FAILURE_ID = 21791;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ConsoleServerInitialization(_In_ HANDLE Server, const ConsoleArguments* const args)
|
[[nodiscard]] HRESULT ConsoleServerInitialization(const ConsoleArguments& args)
|
||||||
{
|
{
|
||||||
Globals& Globals = ServiceLocator::LocateGlobals();
|
Globals& Globals = ServiceLocator::LocateGlobals();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Globals.pDeviceComm = new DeviceComm(Server);
|
Globals.pDeviceComm = new DeviceComm(args.GetServerHandle());
|
||||||
|
|
||||||
Globals.launchArgs = *args;
|
Globals.launchArgs = args;
|
||||||
|
|
||||||
Globals.uiOEMCP = GetOEMCP();
|
Globals.uiOEMCP = GetOEMCP();
|
||||||
Globals.uiWindowsCP = GetACP();
|
Globals.uiWindowsCP = GetACP();
|
||||||
@@ -245,10 +246,10 @@ void ConsoleCheckDebug()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(_In_ HANDLE Server, const ConsoleArguments* const args)
|
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(const ConsoleArguments& args)
|
||||||
{
|
{
|
||||||
auto& g = ServiceLocator::LocateGlobals();
|
auto& g = ServiceLocator::LocateGlobals();
|
||||||
RETURN_IF_FAILED(ConsoleServerInitialization(Server, args));
|
RETURN_IF_FAILED(ConsoleServerInitialization(args));
|
||||||
RETURN_IF_FAILED(g.hConsoleInputInitEvent.create(wil::EventOptions::None));
|
RETURN_IF_FAILED(g.hConsoleInputInitEvent.create(wil::EventOptions::None));
|
||||||
|
|
||||||
// Set up and tell the driver about the input available event.
|
// Set up and tell the driver about the input available event.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <future>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -9,10 +9,21 @@
|
|||||||
|
|
||||||
#include "winbasep.h"
|
#include "winbasep.h"
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForServerHandle(const HANDLE ServerHandle,
|
#include "..\types\Manager.h"
|
||||||
const ConsoleArguments* const args)
|
#include "..\host\ConsoleArguments.hpp"
|
||||||
|
|
||||||
|
[[nodiscard]] HRESULT Entrypoints::StartConsoleForServerHandle(const ConsoleArguments& args)
|
||||||
{
|
{
|
||||||
return ConsoleCreateIoThreadLegacy(ServerHandle, args);
|
if (args.ShouldSendToManager())
|
||||||
|
{
|
||||||
|
if (Manager::s_TrySendToManager(args.GetServerHandle()))
|
||||||
|
{
|
||||||
|
SleepEx(INFINITE, FALSE);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@@ -20,9 +31,17 @@
|
|||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4702)
|
#pragma warning(disable : 4702)
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Entrypoints::StartConsoleForCmdLine(_In_ PCWSTR pwszCmdLine,
|
[[nodiscard]] HRESULT Entrypoints::StartConsoleForCmdLine(ConsoleArguments& args)
|
||||||
const ConsoleArguments* const 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,7 +58,8 @@
|
|||||||
L"\\Reference",
|
L"\\Reference",
|
||||||
FALSE));
|
FALSE));
|
||||||
|
|
||||||
RETURN_IF_NTSTATUS_FAILED(Entrypoints::StartConsoleForServerHandle(ServerHandle.get(), args));
|
args.SetServerHandle(ServerHandle.get());
|
||||||
|
RETURN_IF_NTSTATUS_FAILED(Entrypoints::StartConsoleForServerHandle(args));
|
||||||
|
|
||||||
// If we get to here, we have transferred ownership of the server handle to the console, so release it.
|
// If we get to here, we have transferred ownership of the server handle to the console, so release it.
|
||||||
// Keep a copy of the value so we can open the client handles even though we're no longer the owner.
|
// Keep a copy of the value so we can open the client handles even though we're no longer the owner.
|
||||||
@@ -143,6 +163,8 @@
|
|||||||
NULL));
|
NULL));
|
||||||
|
|
||||||
// We have to copy the command line string we're given because CreateProcessW has to be called with mutable data.
|
// We have to copy the command line string we're given because CreateProcessW has to be called with mutable data.
|
||||||
|
PCWSTR pwszCmdLine = args.GetClientCommandline().data();
|
||||||
|
|
||||||
if (wcslen(pwszCmdLine) == 0)
|
if (wcslen(pwszCmdLine) == 0)
|
||||||
{
|
{
|
||||||
// If they didn't give us one, just launch cmd.exe.
|
// If they didn't give us one, just launch cmd.exe.
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ class ConsoleArguments;
|
|||||||
|
|
||||||
namespace Entrypoints
|
namespace Entrypoints
|
||||||
{
|
{
|
||||||
[[nodiscard]] HRESULT StartConsoleForServerHandle(const HANDLE ServerHandle, const ConsoleArguments* const args);
|
[[nodiscard]] HRESULT StartConsoleForServerHandle(const ConsoleArguments& args);
|
||||||
[[nodiscard]] HRESULT StartConsoleForCmdLine(_In_ PCWSTR pwszCmdLine, const ConsoleArguments* const args);
|
[[nodiscard]] HRESULT StartConsoleForCmdLine(ConsoleArguments& args);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,4 +5,4 @@
|
|||||||
|
|
||||||
class ConsoleArguments;
|
class ConsoleArguments;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(_In_ HANDLE Server, const ConsoleArguments* const args);
|
[[nodiscard]] HRESULT ConsoleCreateIoThreadLegacy(const ConsoleArguments& args);
|
||||||
|
|||||||
357
src/types/Manager.cpp
Normal file
357
src/types/Manager.cpp
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
#include "Manager.h"
|
||||||
|
|
||||||
|
static constexpr std::wstring_view MUTEX_NAME = L"Local\\WindowsTerminalManager";
|
||||||
|
static constexpr std::wstring_view PIPE_NAME = L"\\\\.\\pipe\\WindowsTerminalManagerPipe";
|
||||||
|
static constexpr DWORD PIPE_BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
|
Manager::Manager() :
|
||||||
|
_mutex(),
|
||||||
|
_pipe(),
|
||||||
|
_exit(),
|
||||||
|
_theServer(false)
|
||||||
|
{
|
||||||
|
// Create exit event.
|
||||||
|
_exit.create();
|
||||||
|
|
||||||
|
// Try to open the mutex.
|
||||||
|
if (!_mutex.try_open(MUTEX_NAME.data()))
|
||||||
|
{
|
||||||
|
// If we can't open it, create one because no one else did.
|
||||||
|
_mutex.create(MUTEX_NAME.data());
|
||||||
|
_theServer = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If it could just be opened, we're not the server.
|
||||||
|
_theServer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're the server, establish communication listener and thread
|
||||||
|
if (_theServer)
|
||||||
|
{
|
||||||
|
_becomeServer();
|
||||||
|
}
|
||||||
|
// If we're not the server, find out who it is so we can get notified when they leave and become the server.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ManagerMessageQuery query;
|
||||||
|
query.size = sizeof(query);
|
||||||
|
query.type = ManagerMessageTypes::GetManagerPid;
|
||||||
|
|
||||||
|
const auto reply = _ask(query);
|
||||||
|
|
||||||
|
_waitToBecomeServer = std::async(std::launch::async, [reply, this] {
|
||||||
|
|
||||||
|
wil::unique_handle managerProcess(OpenProcess(SYNCHRONIZE, FALSE, reply.reply.getPid.id));
|
||||||
|
THROW_LAST_ERROR_IF_NULL(managerProcess.get());
|
||||||
|
|
||||||
|
WaitForSingleObject(managerProcess.get(), INFINITE);
|
||||||
|
_becomeServer();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager::~Manager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::NotifyExit()
|
||||||
|
{
|
||||||
|
_exit.SetEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Manager::s_TrySendToManager(const HANDLE server)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get PID from remote process.
|
||||||
|
ManagerMessageQuery query;
|
||||||
|
query.size = sizeof(query);
|
||||||
|
query.type = ManagerMessageTypes::GetManagerPid;
|
||||||
|
|
||||||
|
auto reply = _ask(query);
|
||||||
|
const auto processId = reply.reply.getPid.id;
|
||||||
|
|
||||||
|
// Open for handle duping.
|
||||||
|
wil::unique_handle otherProcess(OpenProcess(PROCESS_DUP_HANDLE, FALSE, processId));
|
||||||
|
THROW_LAST_ERROR_IF_NULL(otherProcess.get());
|
||||||
|
|
||||||
|
// Send handle into that process.
|
||||||
|
HANDLE targetHandle;
|
||||||
|
THROW_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), server,
|
||||||
|
otherProcess.get(), &targetHandle,
|
||||||
|
0,
|
||||||
|
FALSE,
|
||||||
|
DUPLICATE_SAME_ACCESS));
|
||||||
|
|
||||||
|
// Tell remote process about new handle ID
|
||||||
|
query.size = sizeof(query);
|
||||||
|
query.type = ManagerMessageTypes::SendConnection;
|
||||||
|
query.query.sendConn.handle = targetHandle;
|
||||||
|
|
||||||
|
reply = _ask(query);
|
||||||
|
|
||||||
|
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 (...)
|
||||||
|
{
|
||||||
|
LOG_CAUGHT_EXCEPTION();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::_becomeServer()
|
||||||
|
{
|
||||||
|
// lock?
|
||||||
|
|
||||||
|
// test if pipe exists?
|
||||||
|
|
||||||
|
_theServer = true;
|
||||||
|
|
||||||
|
// enter loop to make server connections
|
||||||
|
_serverWork = std::async(std::launch::async, [this] {
|
||||||
|
_serverLoop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::_serverLoop()
|
||||||
|
{
|
||||||
|
wil::unique_event newClient;
|
||||||
|
newClient.create(wil::EventOptions::ManualReset);
|
||||||
|
|
||||||
|
bool keepGoing = true;
|
||||||
|
while (keepGoing)
|
||||||
|
{
|
||||||
|
OVERLAPPED overlap = { 0 };
|
||||||
|
overlap.hEvent = newClient.get();
|
||||||
|
|
||||||
|
wil::unique_handle pipe(CreateNamedPipeW(PIPE_NAME.data(),
|
||||||
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||||
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_ACCEPT_REMOTE_CLIENTS,
|
||||||
|
PIPE_UNLIMITED_INSTANCES,
|
||||||
|
PIPE_BUFFER_SIZE,
|
||||||
|
PIPE_BUFFER_SIZE,
|
||||||
|
0,
|
||||||
|
nullptr)); // replace with actual security descriptor?
|
||||||
|
|
||||||
|
THROW_LAST_ERROR_IF(pipe.get() == INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
|
if (!ConnectNamedPipe(pipe.get(), &overlap))
|
||||||
|
{
|
||||||
|
// IO pending and Pipe Connected are OK error codes. Go into the wait.
|
||||||
|
const auto gle = GetLastError();
|
||||||
|
if (gle != ERROR_IO_PENDING && gle != ERROR_PIPE_CONNECTED)
|
||||||
|
{
|
||||||
|
THROW_LAST_ERROR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<HANDLE, 2> waitOn;
|
||||||
|
waitOn.at(0) = _exit.get();
|
||||||
|
waitOn.at(1) = newClient.get();
|
||||||
|
const auto ret = WaitForMultipleObjects(gsl::narrow<DWORD>(waitOn.size()), waitOn.data(), FALSE, INFINITE);
|
||||||
|
|
||||||
|
if (ret == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
keepGoing = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (ret == WAIT_OBJECT_0 + 1)
|
||||||
|
{
|
||||||
|
const auto loosePipeHandle = pipe.release();
|
||||||
|
auto future = std::async(std::launch::async, [this, loosePipeHandle] {
|
||||||
|
_perClientLoop(wil::unique_handle(loosePipeHandle));
|
||||||
|
});
|
||||||
|
_perClientWork.push_back(std::move(future));
|
||||||
|
}
|
||||||
|
else if (ret == WAIT_FAILED)
|
||||||
|
{
|
||||||
|
THROW_LAST_ERROR();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
THROW_WIN32(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::_perClientLoop(wil::unique_handle pipe)
|
||||||
|
{
|
||||||
|
/*bool keepGoing = true;
|
||||||
|
while (keepGoing)*/
|
||||||
|
{
|
||||||
|
ManagerMessageQuery query;
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
SetLastError(S_OK);
|
||||||
|
const auto result = ReadFile(pipe.get(),
|
||||||
|
&query,
|
||||||
|
sizeof(query),
|
||||||
|
&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;
|
||||||
|
switch (query.type)
|
||||||
|
{
|
||||||
|
case ManagerMessageTypes::GetManagerPid:
|
||||||
|
reply = _getPid(query);
|
||||||
|
break;
|
||||||
|
case ManagerMessageTypes::SendConnection:
|
||||||
|
reply = _sendConnection(query);
|
||||||
|
break;
|
||||||
|
case ManagerMessageTypes::SendCmdAndWorking:
|
||||||
|
reply = _sendCmdAndWorking(query, buffer);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
THROW_HR(E_NOTIMPL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD bytesWritten = 0;
|
||||||
|
THROW_IF_WIN32_BOOL_FALSE(WriteFile(pipe.get(),
|
||||||
|
&reply,
|
||||||
|
sizeof(reply),
|
||||||
|
&bytesWritten,
|
||||||
|
nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager::ManagerMessageReply Manager::_ask(Manager::ManagerMessageQuery& query)
|
||||||
|
{
|
||||||
|
ManagerMessageReply reply;
|
||||||
|
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
THROW_IF_WIN32_BOOL_FALSE(CallNamedPipeW(PIPE_NAME.data(),
|
||||||
|
&query,
|
||||||
|
query.size,
|
||||||
|
&reply,
|
||||||
|
sizeof(reply),
|
||||||
|
&bytesRead,
|
||||||
|
NMPWAIT_WAIT_FOREVER));
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager::ManagerMessageReply Manager::_getPid(ManagerMessageQuery /*query*/)
|
||||||
|
{
|
||||||
|
ManagerMessageReply reply;
|
||||||
|
|
||||||
|
reply.type = ManagerMessageTypes::GetManagerPid;
|
||||||
|
reply.reply.getPid.id = GetCurrentProcessId();
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const auto serverHandle = query.query.sendConn.handle;
|
||||||
|
|
||||||
|
// create new conhost connection...
|
||||||
|
for (const auto& func : s_onHandleConnection)
|
||||||
|
{
|
||||||
|
func(serverHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagerMessageReply reply;
|
||||||
|
|
||||||
|
reply.type = ManagerMessageTypes::SendConnection;
|
||||||
|
reply.reply.sendConn.ok = true;
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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;
|
||||||
|
}
|
||||||
|
|
||||||
84
src/types/Manager.h
Normal file
84
src/types/Manager.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
class Manager final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Manager();
|
||||||
|
virtual ~Manager();
|
||||||
|
|
||||||
|
void NotifyExit();
|
||||||
|
|
||||||
|
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 std::wstring_view cmdline,
|
||||||
|
const std::wstring_view workingDir);
|
||||||
|
|
||||||
|
Manager(const Manager&) = delete;
|
||||||
|
Manager(Manager&&) = delete;
|
||||||
|
Manager& operator=(const Manager&) = delete;
|
||||||
|
Manager& operator=(Manager&&) = delete;
|
||||||
|
private:
|
||||||
|
wil::unique_mutex _mutex;
|
||||||
|
wil::unique_event _exit;
|
||||||
|
wil::unique_handle _pipe;
|
||||||
|
bool _theServer;
|
||||||
|
std::future<void> _waitToBecomeServer;
|
||||||
|
std::future<void> _serverWork;
|
||||||
|
std::vector<std::future<void>> _perClientWork;
|
||||||
|
|
||||||
|
enum class ManagerMessageTypes
|
||||||
|
{
|
||||||
|
GetManagerPid,
|
||||||
|
SendConnection,
|
||||||
|
SendCmdAndWorking
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ManagerMessageQuery
|
||||||
|
{
|
||||||
|
DWORD size;
|
||||||
|
ManagerMessageTypes type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct SendConnection
|
||||||
|
{
|
||||||
|
HANDLE handle;
|
||||||
|
} sendConn;
|
||||||
|
struct SendCmdAndWorking
|
||||||
|
{
|
||||||
|
DWORD cmd;
|
||||||
|
DWORD working;
|
||||||
|
} sendCmdAndWorking;
|
||||||
|
} query;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ManagerMessageReply
|
||||||
|
{
|
||||||
|
ManagerMessageTypes type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct GetManagerPid
|
||||||
|
{
|
||||||
|
DWORD id;
|
||||||
|
} getPid;
|
||||||
|
struct SendConnection
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
} sendConn;
|
||||||
|
struct SendCmdAndWorking
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
} sendCmdAndWorking;
|
||||||
|
} reply;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ManagerMessageReply _ask(ManagerMessageQuery& query);
|
||||||
|
static ManagerMessageReply _getPid(ManagerMessageQuery query);
|
||||||
|
static ManagerMessageReply _sendConnection(ManagerMessageQuery query);
|
||||||
|
static ManagerMessageReply _sendCmdAndWorking(ManagerMessageQuery query, std::unique_ptr<byte[]>& buffer);
|
||||||
|
|
||||||
|
void _becomeServer();
|
||||||
|
void _serverLoop();
|
||||||
|
void _perClientLoop(wil::unique_handle pipe);
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<ClCompile Include="..\CodepointWidthDetector.cpp" />
|
<ClCompile Include="..\CodepointWidthDetector.cpp" />
|
||||||
<ClCompile Include="..\convert.cpp" />
|
<ClCompile Include="..\convert.cpp" />
|
||||||
<ClCompile Include="..\GlyphWidth.cpp" />
|
<ClCompile Include="..\GlyphWidth.cpp" />
|
||||||
|
<ClCompile Include="..\Manager.cpp" />
|
||||||
<ClCompile Include="..\MouseEvent.cpp" />
|
<ClCompile Include="..\MouseEvent.cpp" />
|
||||||
<ClCompile Include="..\FocusEvent.cpp" />
|
<ClCompile Include="..\FocusEvent.cpp" />
|
||||||
<ClCompile Include="..\IInputEvent.cpp" />
|
<ClCompile Include="..\IInputEvent.cpp" />
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
<ClInclude Include="..\inc\IInputEvent.hpp" />
|
<ClInclude Include="..\inc\IInputEvent.hpp" />
|
||||||
<ClInclude Include="..\inc\Viewport.hpp" />
|
<ClInclude Include="..\inc\Viewport.hpp" />
|
||||||
<ClInclude Include="..\inc\Utf16Parser.hpp" />
|
<ClInclude Include="..\inc\Utf16Parser.hpp" />
|
||||||
|
<ClInclude Include="..\Manager.h" />
|
||||||
<ClInclude Include="..\precomp.h" />
|
<ClInclude Include="..\precomp.h" />
|
||||||
<ClInclude Include="..\utils.hpp" />
|
<ClInclude Include="..\utils.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -39,4 +41,4 @@
|
|||||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||||
<Import Project="$(SolutionDir)src\common.build.lib.props" />
|
<Import Project="$(SolutionDir)src\common.build.lib.props" />
|
||||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -57,6 +57,9 @@
|
|||||||
<ClCompile Include="..\utils.cpp">
|
<ClCompile Include="..\utils.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Manager.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\inc\IInputEvent.hpp">
|
<ClInclude Include="..\inc\IInputEvent.hpp">
|
||||||
@@ -83,6 +86,9 @@
|
|||||||
<ClInclude Include="..\utils.hpp">
|
<ClInclude Include="..\utils.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Manager.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ SOURCES= \
|
|||||||
..\FocusEvent.cpp \
|
..\FocusEvent.cpp \
|
||||||
..\GlyphWidth.cpp \
|
..\GlyphWidth.cpp \
|
||||||
..\KeyEvent.cpp \
|
..\KeyEvent.cpp \
|
||||||
|
..\Manager.cpp \
|
||||||
..\MenuEvent.cpp \
|
..\MenuEvent.cpp \
|
||||||
..\ModifierKeyState.cpp \
|
..\ModifierKeyState.cpp \
|
||||||
..\MouseEvent.cpp \
|
..\MouseEvent.cpp \
|
||||||
|
|||||||
Reference in New Issue
Block a user