Compare commits

...

2 Commits

Author SHA1 Message Date
Mike Griese
3bed10aed0 fix the build 2023-01-17 13:37:36 -06:00
Mike Griese
68d854011e This is attmept 3 at fixing #13388
In this commit, we pass the owner's HWND on the commandline to conpty. That
  means conpty will always have the hwnd by the time the window is created.
2023-01-17 13:20:19 -06:00
12 changed files with 74 additions and 28 deletions

View File

@@ -41,7 +41,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// - phOutput: Receives the handle to the newly-created anonymous pipe for reading the output of the conpty.
// - phPc: Receives a token value to identify this conpty
#pragma warning(suppress : 26430) // This statement sufficiently checks the out parameters. Analyzer cannot find this.
static HRESULT _CreatePseudoConsoleAndPipes(const COORD size, const DWORD dwFlags, HANDLE* phInput, HANDLE* phOutput, HPCON* phPC) noexcept
static HRESULT _CreatePseudoConsoleAndPipes(const COORD size, const DWORD dwFlags, HWND ownerHwnd, HANDLE* phInput, HANDLE* phOutput, HPCON* phPC) noexcept
{
RETURN_HR_IF(E_INVALIDARG, phPC == nullptr || phInput == nullptr || phOutput == nullptr);
@@ -50,7 +50,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
RETURN_IF_WIN32_BOOL_FALSE(CreatePipe(&inPipePseudoConsoleSide, &inPipeOurSide, nullptr, 0));
RETURN_IF_WIN32_BOOL_FALSE(CreatePipe(&outPipeOurSide, &outPipePseudoConsoleSide, nullptr, 0));
RETURN_IF_FAILED(ConptyCreatePseudoConsole(size, inPipePseudoConsoleSide.get(), outPipePseudoConsoleSide.get(), dwFlags, phPC));
RETURN_IF_FAILED(ConptyCreatePseudoConsoleWithWindow(ownerHwnd, INVALID_HANDLE_VALUE, size, inPipePseudoConsoleSide.get(), outPipePseudoConsoleSide.get(), dwFlags, phPC));
*phInput = inPipeOurSide.release();
*phOutput = outPipeOurSide.release();
return S_OK;
@@ -338,12 +338,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
}
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(til::unwrap_coord_size(dimensions), flags, &_inPipe, &_outPipe, &_hPC));
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(til::unwrap_coord_size(dimensions), flags, reinterpret_cast<HWND>(_initialParentHwnd), &_inPipe, &_outPipe, &_hPC));
if (_initialParentHwnd != 0)
{
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
}
// if (_initialParentHwnd != 0)
// {
// THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
// }
// GH#12515: The conpty assumes it's hidden at the start. If we're visible, let it know now.
if (_initialVisibility)

View File

@@ -25,6 +25,7 @@ const std::wstring_view ConsoleArguments::FEATURE_ARG = L"--feature";
const std::wstring_view ConsoleArguments::FEATURE_PTY_ARG = L"pty";
const std::wstring_view ConsoleArguments::COM_SERVER_ARG = L"-Embedding";
const std::wstring_view ConsoleArguments::PASSTHROUGH_ARG = L"--passthrough";
const std::wstring_view ConsoleArguments::OWNER_ARG = L"--owner";
// NOTE: Thinking about adding more commandline args that control conpty, for
// the Terminal? Make sure you add them to the commandline in
// ConsoleEstablishHandoff. We use that to initialize the ConsoleArguments for a
@@ -124,6 +125,7 @@ ConsoleArguments::ConsoleArguments(const std::wstring& commandline,
_width = 0;
_height = 0;
_inheritCursor = false;
_ownerHwnd = 0;
}
ConsoleArguments::ConsoleArguments() :
@@ -150,6 +152,7 @@ ConsoleArguments& ConsoleArguments::operator=(const ConsoleArguments& other)
_inheritCursor = other._inheritCursor;
_runAsComServer = other._runAsComServer;
_forceNoHandoff = other._forceNoHandoff;
_ownerHwnd = other._ownerHwnd;
}
return *this;
@@ -521,6 +524,17 @@ void ConsoleArguments::s_ConsumeArg(_Inout_ std::vector<std::wstring>& args, _In
s_ConsumeArg(args, i);
hr = S_OK;
}
else if (arg == OWNER_ARG)
{
std::wstring ownerHwndVal;
hr = s_GetArgumentValue(args, i, &ownerHwndVal);
if (SUCCEEDED(hr))
{
std::ignore = s_ParseHandleArg(ownerHwndVal, _ownerHwnd);
// We actually don't care if this fails to parse. "0x0" is gonna parse as 0 and return E_INVALIDARG, and that's a totally fine result to return
}
}
else if (arg == CLIENT_COMMANDLINE_ARG)
{
// Everything after this is the explicit commandline
@@ -681,6 +695,10 @@ bool ConsoleArguments::IsWin32InputModeEnabled() const
{
return _win32InputMode;
}
HWND ConsoleArguments::GetOwnerHwnd() const
{
return static_cast<HWND>(ULongToHandle( _ownerHwnd ));
}
#ifdef UNIT_TESTING
// Method Description:

View File

@@ -57,6 +57,8 @@ public:
bool IsResizeQuirkEnabled() const;
bool IsWin32InputModeEnabled() const;
HWND GetOwnerHwnd() const;
#ifdef UNIT_TESTING
void EnableConptyModeForTests();
#endif
@@ -79,6 +81,7 @@ public:
static const std::wstring_view FEATURE_PTY_ARG;
static const std::wstring_view COM_SERVER_ARG;
static const std::wstring_view PASSTHROUGH_ARG;
static const std::wstring_view OWNER_ARG;
private:
#ifdef UNIT_TESTING
@@ -98,7 +101,8 @@ private:
const DWORD signalHandle,
const bool inheritCursor,
const bool runAsComServer,
const bool passthroughMode) :
const bool passthroughMode,
const DWORD ownerHwnd = 0) :
_commandline(commandline),
_clientCommandline(clientCommandline),
_vtInHandle(vtInHandle),
@@ -115,7 +119,8 @@ private:
_inheritCursor(inheritCursor),
_resizeQuirk(false),
_runAsComServer{ runAsComServer },
_passthroughMode{ passthroughMode }
_passthroughMode{ passthroughMode },
_ownerHwnd{ ownerHwnd }
{
}
#endif
@@ -145,6 +150,7 @@ private:
bool _inheritCursor;
bool _resizeQuirk{ false };
bool _win32InputMode{ false };
DWORD _ownerHwnd{ 0 };
[[nodiscard]] HRESULT _GetClientCommandline(_Inout_ std::vector<std::wstring>& args,
const size_t index,
@@ -195,6 +201,7 @@ namespace WEX
L"Inherit Cursor: '%ws'\r\n",
L"Run As Com Server: '%ws'\r\n",
L"Passthrough Mode: '%ws'\r\n",
L"Owner HWND: '0x%x'\r\n",
ci.GetClientCommandline().c_str(),
s_ToBoolString(ci.HasVtHandles()),
ci.GetVtInHandle(),
@@ -210,7 +217,8 @@ namespace WEX
ci.GetSignalHandle(),
s_ToBoolString(ci.GetInheritCursor()),
s_ToBoolString(ci.ShouldRunAsComServer()),
s_ToBoolString(ci.IsPassthroughMode()));
s_ToBoolString(ci.IsPassthroughMode()),
ci.GetOwnerHwnd());
}
private:
@@ -241,7 +249,8 @@ namespace WEX
expected.GetSignalHandle() == actual.GetSignalHandle() &&
expected.GetInheritCursor() == actual.GetInheritCursor() &&
expected.ShouldRunAsComServer() == actual.ShouldRunAsComServer() &&
expected.IsPassthroughMode() == actual.IsPassthroughMode();
expected.IsPassthroughMode() == actual.IsPassthroughMode() &&
expected.GetOwnerHwnd() == actual.GetOwnerHwnd();
}
static bool AreSame(const ConsoleArguments& expected, const ConsoleArguments& actual)
@@ -268,7 +277,8 @@ namespace WEX
(object.GetSignalHandle() == 0 || object.GetSignalHandle() == INVALID_HANDLE_VALUE) &&
!object.GetInheritCursor() &&
!object.ShouldRunAsComServer() &&
!object.IsPassthroughMode();
!object.IsPassthroughMode() &&
object.GetOwnerHwnd() == 0;
}
};
}

View File

@@ -85,9 +85,9 @@ void PtySignalInputThread::ConnectConsole() noexcept
// this here ensures that the window is first created with the initial owner
// set up (if so specified).
// - Refer to GH#13066 for details.
void PtySignalInputThread::CreatePseudoWindow()
void PtySignalInputThread::CreatePseudoWindow(HWND ownerHwnd /*= HWND_DESKTOP*/)
{
HWND owner = _earlyReparent.has_value() ? reinterpret_cast<HWND>((*_earlyReparent).handle) : HWND_DESKTOP;
HWND owner = _earlyReparent.has_value() ? reinterpret_cast<HWND>((*_earlyReparent).handle) : ownerHwnd;
ServiceLocator::LocatePseudoWindow(owner);
}

View File

@@ -33,7 +33,7 @@ namespace Microsoft::Console
PtySignalInputThread& operator=(const PtySignalInputThread&) = delete;
void ConnectConsole() noexcept;
void CreatePseudoWindow();
void CreatePseudoWindow(HWND ownerHwnd);
private:
enum class PtySignal : unsigned short

View File

@@ -74,6 +74,7 @@ VtIo::VtIo() :
_resizeQuirk = pArgs->IsResizeQuirkEnabled();
_win32InputMode = pArgs->IsWin32InputModeEnabled();
_passthroughMode = pArgs->IsPassthroughMode();
_originalOwnerHwnd = pArgs->GetOwnerHwnd();
// If we were already given VT handles, set up the VT IO engine to use those.
if (pArgs->InConptyMode())
@@ -329,7 +330,7 @@ void VtIo::CreatePseudoWindow()
{
if (_pPtySignalInputThread)
{
_pPtySignalInputThread->CreatePseudoWindow();
_pPtySignalInputThread->CreatePseudoWindow(_originalOwnerHwnd);
}
else
{

View File

@@ -71,6 +71,7 @@ namespace Microsoft::Console::VirtualTerminal
bool _win32InputMode{ false };
bool _passthroughMode{ false };
bool _closeEventSent{ false };
HWND _originalOwnerHwnd{ HWND_DESKTOP };
std::unique_ptr<Microsoft::Console::Render::VtEngine> _pVtRenderEngine;
std::unique_ptr<Microsoft::Console::VtInputThread> _pVtInputThread;

View File

@@ -29,6 +29,7 @@
CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(HANDLE hToken, COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsoleWithWindow(HWND hOwner, HANDLE hToken, COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
CONPTY_EXPORT HRESULT WINAPI ConptyResizePseudoConsole(HPCON hPC, COORD size);
CONPTY_EXPORT HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC);

View File

@@ -2,6 +2,7 @@ EXPORTS
; Plain old normal aliases
ConptyCreatePseudoConsole
ConptyCreatePseudoConsoleAsUser
ConptyCreatePseudoConsoleWithWindow
ConptyResizePseudoConsole
ConptyClosePseudoConsole
ConptyClosePseudoConsoleTimeout

View File

@@ -109,7 +109,7 @@ static HRESULT _CreatePseudoConsole(const COORD size,
const DWORD dwFlags,
_Inout_ PseudoConsole* pPty)
{
return _CreatePseudoConsole(INVALID_HANDLE_VALUE, size, hInput, hOutput, dwFlags, pPty);
return _CreatePseudoConsole(HWND_DESKTOP, INVALID_HANDLE_VALUE, size, hInput, hOutput, dwFlags, pPty);
}
static HRESULT AttachPseudoConsole(HPCON hPC, std::wstring command, PROCESS_INFORMATION* ppi)

View File

@@ -93,7 +93,8 @@ static bool _HandleIsValid(HANDLE h) noexcept
return (h != INVALID_HANDLE_VALUE) && (h != nullptr);
}
HRESULT _CreatePseudoConsole(const HANDLE hToken,
HRESULT _CreatePseudoConsole(const HWND hOwner,
const HANDLE hToken,
const COORD size,
const HANDLE hInput,
const HANDLE hOutput,
@@ -133,7 +134,7 @@ HRESULT _CreatePseudoConsole(const HANDLE hToken,
RETURN_IF_WIN32_BOOL_FALSE(SetHandleInformation(signalPipeConhostSide.get(), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));
// GH4061: Ensure that the path to executable in the format is escaped so C:\Program.exe cannot collide with C:\Program Files
auto pwszFormat = L"\"%s\" --headless %s%s%s%s--width %hu --height %hu --signal 0x%x --server 0x%x";
auto pwszFormat = L"\"%s\" --headless %s%s%s%s--width %hu --height %hu --signal 0x%x --server 0x%x --owner 0x%x";
// This is plenty of space to hold the formatted string
wchar_t cmd[MAX_PATH]{};
const BOOL bInheritCursor = (dwFlags & PSEUDOCONSOLE_INHERIT_CURSOR) == PSEUDOCONSOLE_INHERIT_CURSOR;
@@ -151,7 +152,8 @@ HRESULT _CreatePseudoConsole(const HANDLE hToken,
size.X,
size.Y,
signalPipeConhostSide.get(),
serverHandle.get());
serverHandle.get(),
hOwner);
STARTUPINFOEXW siEx{ 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEXW);
@@ -440,12 +442,13 @@ extern "C" HRESULT WINAPI ConptyCreatePseudoConsole(_In_ COORD size,
return ConptyCreatePseudoConsoleAsUser(INVALID_HANDLE_VALUE, size, hInput, hOutput, dwFlags, phPC);
}
extern "C" HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(_In_ HANDLE hToken,
_In_ COORD size,
_In_ HANDLE hInput,
_In_ HANDLE hOutput,
_In_ DWORD dwFlags,
_Out_ HPCON* phPC)
extern "C" HRESULT WINAPI ConptyCreatePseudoConsoleWithWindow(_In_ HWND hOwner,
_In_ HANDLE hToken,
_In_ COORD size,
_In_ HANDLE hInput,
_In_ HANDLE hOutput,
_In_ DWORD dwFlags,
_Out_ HPCON* phPC)
{
if (phPC == nullptr)
{
@@ -468,7 +471,7 @@ extern "C" HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(_In_ HANDLE hToken,
RETURN_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), hInput, GetCurrentProcess(), duplicatedInput.addressof(), 0, TRUE, DUPLICATE_SAME_ACCESS));
RETURN_IF_WIN32_BOOL_FALSE(DuplicateHandle(GetCurrentProcess(), hOutput, GetCurrentProcess(), duplicatedOutput.addressof(), 0, TRUE, DUPLICATE_SAME_ACCESS));
RETURN_IF_FAILED(_CreatePseudoConsole(hToken, size, duplicatedInput.get(), duplicatedOutput.get(), dwFlags, pPty));
RETURN_IF_FAILED(_CreatePseudoConsole(hOwner, hToken, size, duplicatedInput.get(), duplicatedOutput.get(), dwFlags, pPty));
*phPC = (HPCON)pPty;
cleanupPty.release();
@@ -476,6 +479,16 @@ extern "C" HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(_In_ HANDLE hToken,
return S_OK;
}
extern "C" HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(_In_ HANDLE hToken,
_In_ COORD size,
_In_ HANDLE hInput,
_In_ HANDLE hOutput,
_In_ DWORD dwFlags,
_Out_ HPCON* phPC)
{
return ConptyCreatePseudoConsoleWithWindow(HWND_DESKTOP, hToken, size, hInput, hOutput, dwFlags, phPC);
}
// Function Description:
// Resizes the given conpty to the specified size, in characters.
extern "C" HRESULT WINAPI ConptyResizePseudoConsole(_In_ HPCON hPC, _In_ COORD size)

View File

@@ -63,7 +63,8 @@ typedef struct _PseudoConsole
#endif
// Implementations of the various PseudoConsole functions.
HRESULT _CreatePseudoConsole(const HANDLE hToken,
HRESULT _CreatePseudoConsole(const HWND hOwner,
const HANDLE hToken,
const COORD size,
const HANDLE hInput,
const HANDLE hOutput,