mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-20 02:19:50 -05:00
Merge commit '26d67d9c0af0a05b0e65aa76537006862d39535b' into dev/miniksa/msgs
This commit is contained in:
1
.github/actions/spelling/allow/apis.txt
vendored
1
.github/actions/spelling/allow/apis.txt
vendored
@@ -145,6 +145,7 @@ REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
ROOTOWNER
|
||||
RSHIFT
|
||||
SACL
|
||||
schandle
|
||||
|
||||
@@ -60,6 +60,12 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Method Description:
|
||||
// - implements the IInitializeWithWindow interface from shobjidl_core.
|
||||
// - We're going to use this HWND as the owner for the ConPTY windows, via
|
||||
// ConptyConnection::ReparentWindow. We need this for applications that
|
||||
// call GetConsoleWindow, and attempt to open a MessageBox for the
|
||||
// console. By marking the conpty windows as owned by the Terminal HWND,
|
||||
// the message box will be owned by the Terminal window as well.
|
||||
// - see GH#2988
|
||||
HRESULT TerminalPage::Initialize(HWND hwnd)
|
||||
{
|
||||
_hostingHwnd = hwnd;
|
||||
@@ -2429,6 +2435,10 @@ namespace winrt::TerminalApp::implementation
|
||||
term.WindowVisibilityChanged(_visible);
|
||||
}
|
||||
|
||||
if (_hostingHwnd.has_value())
|
||||
{
|
||||
term.OwningHwnd(reinterpret_cast<uint64_t>(*_hostingHwnd));
|
||||
}
|
||||
return term;
|
||||
}
|
||||
|
||||
|
||||
@@ -316,6 +316,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
|
||||
}
|
||||
if (_initialParentHwnd != 0)
|
||||
{
|
||||
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(_LaunchAttachedClient());
|
||||
}
|
||||
@@ -334,6 +338,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), dimensions));
|
||||
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
|
||||
}
|
||||
|
||||
_startTime = std::chrono::high_resolution_clock::now();
|
||||
@@ -502,6 +507,22 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ConptyConnection::ReparentWindow(const uint64_t newParent)
|
||||
{
|
||||
// If we haven't started connecting at all, stash this HWND to use once we have started.
|
||||
if (!_isStateAtOrBeyond(ConnectionState::Connecting))
|
||||
{
|
||||
_initialParentHwnd = newParent;
|
||||
}
|
||||
// Otherwise, just inform the conpty of the new owner window handle.
|
||||
// This shouldn't be hittable until GH#5000 / GH#1256, when it's
|
||||
// possible to reparent terminals to different windows.
|
||||
else if (_isConnected())
|
||||
{
|
||||
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(newParent)));
|
||||
}
|
||||
}
|
||||
|
||||
void ConptyConnection::Close() noexcept
|
||||
try
|
||||
{
|
||||
|
||||
@@ -35,8 +35,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void Close() noexcept;
|
||||
void ClearBuffer();
|
||||
|
||||
void ShowHide(const bool show);
|
||||
|
||||
void ReparentWindow(const uint64_t newParent);
|
||||
|
||||
winrt::guid Guid() const noexcept;
|
||||
winrt::hstring Commandline() const;
|
||||
|
||||
@@ -66,6 +69,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
uint32_t _initialRows{};
|
||||
uint32_t _initialCols{};
|
||||
uint64_t _initialParentHwnd{ 0 };
|
||||
hstring _commandline{};
|
||||
hstring _startingDirectory{};
|
||||
hstring _startingTitle{};
|
||||
|
||||
@@ -14,8 +14,11 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
String Commandline { get; };
|
||||
|
||||
void ClearBuffer();
|
||||
|
||||
void ShowHide(Boolean show);
|
||||
|
||||
void ReparentWindow(UInt64 newParent);
|
||||
|
||||
static event NewConnectionHandler NewConnection;
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
|
||||
@@ -265,6 +265,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto height = vp.Height();
|
||||
_connection.Resize(height, width);
|
||||
|
||||
if (_OwningHwnd != 0)
|
||||
{
|
||||
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
|
||||
{
|
||||
conpty.ReparentWindow(_OwningHwnd);
|
||||
}
|
||||
}
|
||||
|
||||
// Override the default width and height to match the size of the swapChainPanel
|
||||
_settings->InitialCols(width);
|
||||
_settings->InitialRows(height);
|
||||
|
||||
@@ -170,6 +170,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
// TODO:GH#1256 - When a tab can be torn out or otherwise reparented to
|
||||
// another window, this value will need a custom setter, so that we can
|
||||
// also update the connection.
|
||||
WINRT_PROPERTY(uint64_t, OwningHwnd, 0);
|
||||
|
||||
RUNTIME_SETTING(double, Opacity, _settings->Opacity());
|
||||
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());
|
||||
|
||||
|
||||
@@ -24,5 +24,8 @@ namespace Microsoft.Terminal.Control
|
||||
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
||||
|
||||
Microsoft.Terminal.Core.Scheme ColorScheme { get; set; };
|
||||
|
||||
UInt64 OwningHwnd;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2807,4 +2807,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::OwningHwnd(uint64_t owner)
|
||||
{
|
||||
_core.OwningHwnd(owner);
|
||||
}
|
||||
|
||||
uint64_t TermControl::OwningHwnd()
|
||||
{
|
||||
return _core.OwningHwnd();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
double BackgroundOpacity() const;
|
||||
|
||||
uint64_t OwningHwnd();
|
||||
void OwningHwnd(uint64_t owner);
|
||||
#pragma endregion
|
||||
|
||||
void ScrollViewport(int viewTop);
|
||||
|
||||
@@ -41,6 +41,11 @@ IslandWindow::~IslandWindow()
|
||||
_source.Close();
|
||||
}
|
||||
|
||||
HWND IslandWindow::GetInteropHandle() const
|
||||
{
|
||||
return _interopWindowHandle;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create the actual window that we'll use for the application.
|
||||
// Arguments:
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
virtual void MakeWindow() noexcept;
|
||||
void Close();
|
||||
virtual void OnSize(const UINT width, const UINT height);
|
||||
HWND GetInteropHandle() const;
|
||||
|
||||
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
|
||||
void OnResize(const UINT width, const UINT height) override;
|
||||
|
||||
@@ -56,6 +56,10 @@ DWORD WINAPI PtySignalInputThread::StaticThreadProc(_In_ LPVOID lpParameter)
|
||||
// (in and screen buffers) haven't yet been initialized.
|
||||
// - NOTE: Call under LockConsole() to ensure other threads have an opportunity
|
||||
// to set early-work state.
|
||||
// - We need to do this specifically on the thread with the message pump. If the
|
||||
// window is created on another thread, then the window won't have a message
|
||||
// pump associated with it, and a DPI change in the connected terminal could
|
||||
// end up HANGING THE CONPTY (for example).
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
@@ -71,6 +75,12 @@ void PtySignalInputThread::ConnectConsole() noexcept
|
||||
{
|
||||
_DoShowHide(_initialShowHide->show);
|
||||
}
|
||||
|
||||
// If we were given a owner HWND, then manually start the pseudo window now.
|
||||
if (_earlyReparent)
|
||||
{
|
||||
_DoSetWindowParent(*_earlyReparent);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -150,6 +160,28 @@ void PtySignalInputThread::ConnectConsole() noexcept
|
||||
|
||||
break;
|
||||
}
|
||||
case PtySignal::SetParent:
|
||||
{
|
||||
SetParentData reparentMessage = { 0 };
|
||||
_GetData(&reparentMessage, sizeof(reparentMessage));
|
||||
|
||||
LockConsole();
|
||||
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
||||
|
||||
// If the client app hasn't yet connected, stash the new owner.
|
||||
// We'll later (PtySignalInputThread::ConnectConsole) use the value
|
||||
// to set up the owner of the conpty window.
|
||||
if (!_consoleConnected)
|
||||
{
|
||||
_earlyReparent = reparentMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
_DoSetWindowParent(reparentMessage);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
THROW_HR(E_UNEXPECTED);
|
||||
@@ -183,6 +215,20 @@ void PtySignalInputThread::_DoShowHide(const bool show)
|
||||
_pConApi->ShowWindow(show);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update the owner of the pseudo-window we're using for the conpty HWND. This
|
||||
// allows to mark the pseudoconsole windows as "owner" by the terminal HWND
|
||||
// that's actually hosting them.
|
||||
// - Refer to GH#2988
|
||||
// Arguments:
|
||||
// - data - Packet information containing owner HWND information
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void PtySignalInputThread::_DoSetWindowParent(const SetParentData& data)
|
||||
{
|
||||
_pConApi->ReparentWindow(data.handle);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Retrieves bytes from the file stream and exits or throws errors should the pipe state
|
||||
// be compromised.
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace Microsoft::Console
|
||||
{
|
||||
ShowHideWindow = 1,
|
||||
ClearBuffer = 2,
|
||||
SetParent = 3,
|
||||
ResizeWindow = 8
|
||||
};
|
||||
|
||||
@@ -50,14 +51,21 @@ namespace Microsoft::Console
|
||||
unsigned short sx;
|
||||
unsigned short sy;
|
||||
};
|
||||
|
||||
struct ShowHideData
|
||||
{
|
||||
unsigned short show; // used as a bool, but passed as a ushort
|
||||
};
|
||||
|
||||
struct SetParentData
|
||||
{
|
||||
uint64_t handle;
|
||||
};
|
||||
|
||||
[[nodiscard]] HRESULT _InputThread();
|
||||
bool _GetData(_Out_writes_bytes_(cbBuffer) void* const pBuffer, const DWORD cbBuffer);
|
||||
void _DoResizeWindow(const ResizeWindowData& data);
|
||||
void _DoSetWindowParent(const SetParentData& data);
|
||||
void _DoClearBuffer();
|
||||
void _DoShowHide(const bool show);
|
||||
void _Shutdown();
|
||||
@@ -69,5 +77,8 @@ namespace Microsoft::Console
|
||||
std::optional<ResizeWindowData> _earlyResize;
|
||||
std::optional<ShowHideData> _initialShowHide;
|
||||
std::unique_ptr<Microsoft::Console::VirtualTerminal::ConGetSet> _pConApi;
|
||||
|
||||
public:
|
||||
std::optional<SetParentData> _earlyReparent;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -300,6 +300,11 @@ bool VtIo::IsUsingVt() const
|
||||
|
||||
if (_pPtySignalInputThread)
|
||||
{
|
||||
// IMPORTANT! Start the pseudo window on this thread. This thread has a
|
||||
// message pump. If you DON'T, then a DPI change in the owning hwnd will
|
||||
// cause us to get a dpi change as well, which we'll never deque and
|
||||
// handle, effectively HANGING THE OWNER HWND.
|
||||
//
|
||||
// Let the signal thread know that the console is connected
|
||||
_pPtySignalInputThread->ConnectConsole();
|
||||
}
|
||||
|
||||
@@ -905,3 +905,17 @@ void ConhostInternalGetSet::UpdateSoftFont(const gsl::span<const uint16_t> bitPa
|
||||
pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint);
|
||||
}
|
||||
}
|
||||
|
||||
void ConhostInternalGetSet::ReparentWindow(const uint64_t handle)
|
||||
{
|
||||
// This will initialize s_interactivityFactory for us. It will also
|
||||
// conveniently return 0 when we're on OneCore.
|
||||
//
|
||||
// If the window hasn't been created yet, by some other call to
|
||||
// LocatePseudoWindow, then this will also initialize the owner of the
|
||||
// window.
|
||||
if (const auto psuedoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast<HWND>(handle)) })
|
||||
{
|
||||
LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast<HWND>(handle)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,8 @@ public:
|
||||
const SIZE cellSize,
|
||||
const size_t centeringHint) override;
|
||||
|
||||
void ReparentWindow(const uint64_t handle);
|
||||
|
||||
private:
|
||||
void _modifyLines(const size_t count, const bool insert);
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC);
|
||||
|
||||
HRESULT WINAPI ConptyShowHidePseudoConsole(HPCON hPC, bool show);
|
||||
|
||||
HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newParent);
|
||||
|
||||
VOID WINAPI ConptyClosePseudoConsole(HPCON hPC);
|
||||
|
||||
HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC);
|
||||
|
||||
@@ -289,9 +289,10 @@ using namespace Microsoft::Console::Interactivity;
|
||||
// that GetConsoleWindow returns a real value.
|
||||
// Arguments:
|
||||
// - hwnd: Receives the value of the newly created window's HWND.
|
||||
// - owner: the HWND that should be the initial owner of the pseudo window.
|
||||
// Return Value:
|
||||
// - STATUS_SUCCESS on success, otherwise an appropriate error.
|
||||
[[nodiscard]] NTSTATUS InteractivityFactory::CreatePseudoWindow(HWND& hwnd)
|
||||
[[nodiscard]] NTSTATUS InteractivityFactory::CreatePseudoWindow(HWND& hwnd, const HWND owner)
|
||||
{
|
||||
hwnd = nullptr;
|
||||
ApiLevel level;
|
||||
@@ -311,21 +312,30 @@ using namespace Microsoft::Console::Interactivity;
|
||||
pseudoClass.lpfnWndProc = s_PseudoWindowProc;
|
||||
RegisterClass(&pseudoClass);
|
||||
|
||||
// Note that because we're not specifying WS_CHILD, this window
|
||||
// will become an _owned_ window, not a _child_ window. This is
|
||||
// important - child windows report their position as relative
|
||||
// to their parent window, while owned windows are still
|
||||
// relative to the desktop. (there are other subtleties as well
|
||||
// as far as the difference between parent/child and owner/owned
|
||||
// windows). Evan K said we should do it this way, and he
|
||||
// definitely knows.
|
||||
const auto windowStyle = WS_OVERLAPPEDWINDOW;
|
||||
const auto exStyles = WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_LAYERED;
|
||||
// Attempt to create window
|
||||
|
||||
// Attempt to create window.
|
||||
hwnd = CreateWindowExW(exStyles,
|
||||
PSEUDO_WINDOW_CLASS,
|
||||
nullptr,
|
||||
windowStyle, //WS_CHILD, //WS_OVERLAPPEDWINDOW,
|
||||
windowStyle,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
HWND_DESKTOP, // owner
|
||||
owner,
|
||||
nullptr,
|
||||
nullptr,
|
||||
this);
|
||||
nullptr);
|
||||
|
||||
if (hwnd == nullptr)
|
||||
{
|
||||
@@ -335,7 +345,6 @@ using namespace Microsoft::Console::Interactivity;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BUILD_ONECORE_INTERACTIVITY
|
||||
case ApiLevel::OneCore:
|
||||
hwnd = 0;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Microsoft::Console::Interactivity
|
||||
[[nodiscard]] NTSTATUS CreateAccessibilityNotifier(_Inout_ std::unique_ptr<IAccessibilityNotifier>& notifier);
|
||||
[[nodiscard]] NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider);
|
||||
|
||||
[[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd);
|
||||
[[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd, const HWND owner);
|
||||
void SetPseudoWindowCallback(std::function<void(bool)> func);
|
||||
|
||||
// Wndproc
|
||||
|
||||
@@ -309,10 +309,11 @@ void ServiceLocator::SetPseudoWindowCallback(std::function<void(bool)> func)
|
||||
// Method Description:
|
||||
// - Retrieves the pseudo console window, or attempts to instantiate one.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// - owner: (defaults to 0 `HWND_DESKTOP`) the HWND that should be the initial
|
||||
// owner of the pseudo window.
|
||||
// Return Value:
|
||||
// - a reference to the pseudoconsole window.
|
||||
HWND ServiceLocator::LocatePseudoWindow()
|
||||
HWND ServiceLocator::LocatePseudoWindow(const HWND owner)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
if (!s_pseudoWindowInitialized)
|
||||
@@ -325,7 +326,7 @@ HWND ServiceLocator::LocatePseudoWindow()
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
HWND hwnd;
|
||||
status = s_interactivityFactory->CreatePseudoWindow(hwnd);
|
||||
status = s_interactivityFactory->CreatePseudoWindow(hwnd, owner);
|
||||
s_pseudoWindow.reset(hwnd);
|
||||
}
|
||||
|
||||
@@ -337,8 +338,6 @@ HWND ServiceLocator::LocatePseudoWindow()
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Private Methods
|
||||
|
||||
[[nodiscard]] NTSTATUS ServiceLocator::LoadInteractivityFactory()
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Microsoft::Console::Interactivity
|
||||
[[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider) = 0;
|
||||
|
||||
virtual void SetPseudoWindowCallback(std::function<void(bool)> func) = 0;
|
||||
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0;
|
||||
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd, const HWND owner) = 0;
|
||||
};
|
||||
|
||||
inline IInteractivityFactory::~IInteractivityFactory() {}
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Microsoft::Console::Interactivity
|
||||
static Globals& LocateGlobals();
|
||||
|
||||
static void SetPseudoWindowCallback(std::function<void(bool)> func);
|
||||
static HWND LocatePseudoWindow();
|
||||
static HWND LocatePseudoWindow(const HWND owner = 0 /*HWND_DESKTOP*/);
|
||||
|
||||
protected:
|
||||
ServiceLocator(ServiceLocator const&) = delete;
|
||||
|
||||
@@ -112,5 +112,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
virtual void UpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
|
||||
const SIZE cellSize,
|
||||
const size_t centeringHint) = 0;
|
||||
|
||||
virtual void ReparentWindow(const uint64_t handle) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -428,6 +428,11 @@ public:
|
||||
VERIFY_ARE_EQUAL(_expectedCellSize.cy, cellSize.cy);
|
||||
}
|
||||
|
||||
void ReparentWindow(const uint64_t /*handle*/)
|
||||
{
|
||||
Log::Comment(L"ReparentWindow MOCK called...");
|
||||
}
|
||||
|
||||
void PrepData()
|
||||
{
|
||||
PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter.
|
||||
|
||||
@@ -269,7 +269,6 @@ HRESULT _ShowHidePseudoConsole(_In_ const PseudoConsole* const pPty, const bool
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
unsigned short signalPacket[2];
|
||||
signalPacket[0] = PTY_SIGNAL_SHOWHIDE_WINDOW;
|
||||
signalPacket[1] = show;
|
||||
@@ -278,6 +277,36 @@ HRESULT _ShowHidePseudoConsole(_In_ const PseudoConsole* const pPty, const bool
|
||||
return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
// - Sends a message to the pseudoconsole informing it that it should use the
|
||||
// given window handle as the owner for the conpty's pseudo window. This
|
||||
// allows the response given to GetConsoleWindow() to be a HWND that's owned
|
||||
// by the actual hosting terminal's HWND.
|
||||
// Arguments:
|
||||
// - pPty: A pointer to a PseudoConsole struct.
|
||||
// - newParent: The new owning window
|
||||
// Return Value:
|
||||
// - S_OK if the call succeeded, else an appropriate HRESULT for failing to
|
||||
// write the resize message to the pty.
|
||||
#pragma warning(suppress : 26461)
|
||||
// an HWND is technically a void*, but that confuses static analysis here.
|
||||
HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const HWND newParent)
|
||||
{
|
||||
if (pPty == nullptr)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
// sneaky way to pack a short and a uint64_t in a relatively literal way.
|
||||
#pragma pack(push, 1)
|
||||
struct _signal
|
||||
{
|
||||
const unsigned short id;
|
||||
const uint64_t hwnd;
|
||||
} data{ PTY_SIGNAL_REPARENT_WINDOW, (uint64_t)(newParent) };
|
||||
#pragma pack(pop)
|
||||
const BOOL fSuccess = WriteFile(pPty->hSignal, &data, sizeof(data), nullptr, nullptr);
|
||||
return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - This closes each of the members of a PseudoConsole. It does not free the
|
||||
// data associated with the PseudoConsole. This is helpful for testing,
|
||||
@@ -465,6 +494,22 @@ extern "C" HRESULT WINAPI ConptyShowHidePseudoConsole(_In_ HPCON hPC, bool show)
|
||||
return hr;
|
||||
}
|
||||
|
||||
// - Sends a message to the pseudoconsole informing it that it should use the
|
||||
// given window handle as the owner for the conpty's pseudo window. This
|
||||
// allows the response given to GetConsoleWindow() to be a HWND that's owned
|
||||
// by the actual hosting terminal's HWND.
|
||||
// - Used to support GH#2988
|
||||
extern "C" HRESULT WINAPI ConptyReparentPseudoConsole(_In_ HPCON hPC, HWND newParent)
|
||||
{
|
||||
const PseudoConsole* const pPty = (PseudoConsole*)hPC;
|
||||
HRESULT hr = pPty == nullptr ? E_INVALIDARG : S_OK;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _ReparentPseudoConsole(pPty, newParent);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// Closes the conpty and all associated state.
|
||||
// Client applications attached to the conpty will also behave as though the
|
||||
|
||||
@@ -19,6 +19,7 @@ typedef struct _PseudoConsole
|
||||
// the signal pipe.
|
||||
#define PTY_SIGNAL_SHOWHIDE_WINDOW (1u)
|
||||
#define PTY_SIGNAL_CLEAR_WINDOW (2u)
|
||||
#define PTY_SIGNAL_REPARENT_WINDOW (3u)
|
||||
#define PTY_SIGNAL_RESIZE_WINDOW (8u)
|
||||
|
||||
// CreatePseudoConsole Flags
|
||||
@@ -38,6 +39,7 @@ HRESULT _CreatePseudoConsole(const HANDLE hToken,
|
||||
|
||||
HRESULT _ResizePseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const COORD size);
|
||||
HRESULT _ClearPseudoConsole(_In_ const PseudoConsole* const pPty);
|
||||
HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const HWND newParent);
|
||||
void _ClosePseudoConsoleMembers(_In_ PseudoConsole* pPty);
|
||||
VOID _ClosePseudoConsole(_In_ PseudoConsole* pPty);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user