From 30863d20604fc9496f0422b2e2ef9b5e7c98ad84 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 15 Feb 2022 15:32:01 -0600 Subject: [PATCH 01/15] working on prototypes. I'm not crazy. You're crazy --- src/tools/scratch/Scratch.vcxproj | 10 ++- src/tools/scratch/main.cpp | 126 ++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/src/tools/scratch/Scratch.vcxproj b/src/tools/scratch/Scratch.vcxproj index f2d0141596f..f2493136a37 100644 --- a/src/tools/scratch/Scratch.vcxproj +++ b/src/tools/scratch/Scratch.vcxproj @@ -6,7 +6,7 @@ Scratch Scratch Scratch - Application + Application @@ -21,6 +21,14 @@ Console + + + + + {6bae5851-50d5-4934-8d5e-30361a8a40f3} + + + diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index c6f9cc901a2..72dd46cec2f 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -1,10 +1,136 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +#include "../../inc/LibraryIncludes.h" #include +struct handle_data +{ + unsigned long process_id; + HWND window_handle; +}; + +BOOL is_main_window(HWND handle) +{ + auto owner{ GetWindow(handle, GW_OWNER) }; + // wprintf(fmt::format(L"\t\towner: {}\n", reinterpret_cast(owner)).c_str()); + return owner == (HWND)0 && IsWindowVisible(handle); +} + +BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam) +{ + // wprintf(fmt::format(L"enum_windows_callback\n").c_str()); + handle_data& data = *(handle_data*)lParam; + unsigned long process_id = 0; + GetWindowThreadProcessId(handle, &process_id); + const bool pidDidntMatch{ data.process_id != process_id }; + // wprintf(fmt::format(L"\tpidDidntMatch: {}\n", pidDidntMatch).c_str()); + const bool wasntMainWindow{ !is_main_window(handle) }; + // wprintf(fmt::format(L"\twasntMainWindow: {}\n", wasntMainWindow).c_str()); + if (pidDidntMatch || wasntMainWindow) + { + return TRUE; + } + + wprintf(fmt::format(L"\tpidDidntMatch: {}\n", pidDidntMatch).c_str()); + wprintf(fmt::format(L"\twasntMainWindow: {}\n", wasntMainWindow).c_str()); + + auto owner{ GetWindow(handle, GW_OWNER) }; + wprintf(fmt::format(L"\t\thandle: {}\n", reinterpret_cast(handle)).c_str()); + wprintf(fmt::format(L"\t\towner: {}\n", reinterpret_cast(owner)).c_str()); + + data.window_handle = handle; + return FALSE; +} + +HWND find_main_window(unsigned long process_id) +{ + handle_data data; + data.process_id = process_id; + data.window_handle = 0; + EnumWindows(enum_windows_callback, (LPARAM)&data); + return data.window_handle; +} + +static LRESULT __stdcall WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept +{ + switch (message) + { + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + return DefWindowProc(window, message, wparam, lparam); +} + // This wmain exists for help in writing scratch programs while debugging. int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) { + const auto pid{ GetCurrentProcessId() }; + const auto dumb{ GetConsoleWindow() }; + + wprintf(fmt::format(L"pid: {}\n", pid).c_str()); + wprintf(fmt::format(L"dumb: {}\n", reinterpret_cast(dumb)).c_str()); + + const auto mainHwnd{ find_main_window(pid) }; + wprintf(fmt::format(L"mainHwnd: {}\n", reinterpret_cast(mainHwnd)).c_str()); + + // Register the window class. + const wchar_t CLASS_NAME[] = L"Sample Window Class"; + + WNDCLASS wc = {}; + const auto hInst{ GetModuleHandle(NULL) }; + wc.lpfnWndProc = WndProc; + wc.hInstance = hInst; + wc.lpszClassName = CLASS_NAME; + + RegisterClass(&wc); + + // Create the window. + + HWND hwnd = CreateWindowEx( + 0, // Optional window styles. + CLASS_NAME, // Window class + L"Learn to Program Windows", // Window text + WS_OVERLAPPEDWINDOW, // Window style + + // Size and position + 200, + 200, + 200, + 200, + + NULL, // Parent window + NULL, // Menu + hInst, // Instance handle + NULL // Additional application data + ); + + wprintf(fmt::format(L"hwnd: {}\n", reinterpret_cast(hwnd)).c_str()); + + const auto newHwnd{ find_main_window(pid) }; + wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast(newHwnd)).c_str()); + + if (hwnd == NULL) + { + return 0; + } + + ShowWindow(hwnd, SW_SHOW); + MSG msg = {}; + while (GetMessage(&msg, NULL, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + wprintf(fmt::format(L"window was closed\n").c_str()); + + + wprintf(fmt::format(L"Opening a messagebox...\n").c_str()); + MessageBoxW(NULL, L"foo", L"bar", MB_OK); + wprintf(fmt::format(L"closed a messagebox\n").c_str()); + + return 0; } From 555042ebfe3bd42e106099f39e06fb385e228f51 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 15 Feb 2022 16:37:38 -0600 Subject: [PATCH 02/15] this is totally a hack but it worked better than expected --- .../base/InteractivityFactory.cpp | 13 +++- src/tools/scratch/main.cpp | 64 +++++++++++-------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/interactivity/base/InteractivityFactory.cpp b/src/interactivity/base/InteractivityFactory.cpp index 3c69ebb46bf..1442f4e9a00 100644 --- a/src/interactivity/base/InteractivityFactory.cpp +++ b/src/interactivity/base/InteractivityFactory.cpp @@ -354,7 +354,18 @@ using namespace Microsoft::Console::Interactivity; RegisterClass(&pseudoClass); // Attempt to create window hwnd = CreateWindowExW( - 0, PSEUDO_WINDOW_CLASS, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, HWND_DESKTOP, nullptr, nullptr, nullptr); + 0, + PSEUDO_WINDOW_CLASS, + nullptr, + WS_CHILD, //WS_OVERLAPPEDWINDOW, + 0, + 0, + 0, + 0, + (HWND)0x00070C6A, //HWND_DESKTOP,// parent + nullptr, + nullptr, + nullptr); if (hwnd == nullptr) { DWORD const gle = GetLastError(); diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index 72dd46cec2f..70dafac14b8 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -4,6 +4,9 @@ #include +// Register the window class. +const wchar_t CLASS_NAME[] = L"Sample Window Class"; + struct handle_data { unsigned long process_id; @@ -63,31 +66,12 @@ static LRESULT __stdcall WndProc(HWND const window, UINT const message, WPARAM c return DefWindowProc(window, message, wparam, lparam); } -// This wmain exists for help in writing scratch programs while debugging. -int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) +int doTheWindowThing(HWND hwndToUseAsParent) { - const auto pid{ GetCurrentProcessId() }; - const auto dumb{ GetConsoleWindow() }; - - wprintf(fmt::format(L"pid: {}\n", pid).c_str()); - wprintf(fmt::format(L"dumb: {}\n", reinterpret_cast(dumb)).c_str()); - - const auto mainHwnd{ find_main_window(pid) }; - wprintf(fmt::format(L"mainHwnd: {}\n", reinterpret_cast(mainHwnd)).c_str()); - - // Register the window class. - const wchar_t CLASS_NAME[] = L"Sample Window Class"; - - WNDCLASS wc = {}; const auto hInst{ GetModuleHandle(NULL) }; - wc.lpfnWndProc = WndProc; - wc.hInstance = hInst; - wc.lpszClassName = CLASS_NAME; - - RegisterClass(&wc); + wprintf(fmt::format(L"Creating a Window, then a MessageBox, using {} as the parent HWND\n", reinterpret_cast(hwndToUseAsParent)).c_str()); // Create the window. - HWND hwnd = CreateWindowEx( 0, // Optional window styles. CLASS_NAME, // Window class @@ -100,16 +84,16 @@ int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) 200, 200, - NULL, // Parent window + hwndToUseAsParent, // Parent window NULL, // Menu hInst, // Instance handle NULL // Additional application data ); - wprintf(fmt::format(L"hwnd: {}\n", reinterpret_cast(hwnd)).c_str()); + // wprintf(fmt::format(L"hwnd: {}\n", reinterpret_cast(hwnd)).c_str()); - const auto newHwnd{ find_main_window(pid) }; - wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast(newHwnd)).c_str()); + // const auto newHwnd{ find_main_window(pid) }; + // wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast(newHwnd)).c_str()); if (hwnd == NULL) { @@ -126,11 +110,37 @@ int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) wprintf(fmt::format(L"window was closed\n").c_str()); - wprintf(fmt::format(L"Opening a messagebox...\n").c_str()); - MessageBoxW(NULL, L"foo", L"bar", MB_OK); + MessageBoxW(hwndToUseAsParent, L"foo", L"bar", MB_OK); wprintf(fmt::format(L"closed a messagebox\n").c_str()); + return 0; +} + +// This wmain exists for help in writing scratch programs while debugging. +int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) +{ + const auto pid{ GetCurrentProcessId() }; + const auto dumb{ GetConsoleWindow() }; + + wprintf(fmt::format(L"pid: {}\n", pid).c_str()); + wprintf(fmt::format(L"dumb: {}\n", reinterpret_cast(dumb)).c_str()); + + // const auto mainHwnd{ find_main_window(pid) }; + // wprintf(fmt::format(L"mainHwnd: {}\n", reinterpret_cast(mainHwnd)).c_str()); + + WNDCLASS wc = {}; + const auto hInst{ GetModuleHandle(NULL) }; + wc.lpfnWndProc = WndProc; + wc.hInstance = hInst; + wc.lpszClassName = CLASS_NAME; + + RegisterClass(&wc); + + wprintf(fmt::format(L"Make some windows, using NULL as the parent.\n").c_str()); + doTheWindowThing(nullptr); + wprintf(fmt::format(L"Now, with the console window handle.\n").c_str()); + doTheWindowThing(dumb); return 0; } From 31e9fef447d39ad5e4f6ac44b4460a9ac895abf7 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 17 Feb 2022 16:22:11 -0600 Subject: [PATCH 03/15] I think this plumbs all the way through. DPI is busted tho --- src/cascadia/TerminalApp/AppLogic.h | 2 + src/cascadia/TerminalApp/AppLogic.idl | 2 + src/cascadia/TerminalApp/TerminalPage.cpp | 3 + src/cascadia/TerminalApp/TerminalPage.h | 3 + .../TerminalConnection/ConptyConnection.cpp | 16 ++++ .../TerminalConnection/ConptyConnection.h | 2 + .../TerminalConnection/ConptyConnection.idl | 1 + src/cascadia/TerminalControl/ControlCore.cpp | 5 ++ src/cascadia/TerminalControl/ControlCore.h | 2 + src/cascadia/TerminalControl/ICoreState.idl | 3 + src/cascadia/TerminalControl/TermControl.cpp | 10 +++ src/cascadia/TerminalControl/TermControl.h | 3 + src/cascadia/WindowsTerminal/AppHost.cpp | 1 + src/cascadia/WindowsTerminal/IslandWindow.cpp | 5 ++ src/cascadia/WindowsTerminal/IslandWindow.h | 1 + src/host/PtySignalInputThread.cpp | 29 ++++++ src/host/PtySignalInputThread.hpp | 7 ++ src/host/outputStream.cpp | 10 +++ src/host/outputStream.hpp | 2 + src/inc/conpty-static.h | 2 + .../base/InteractivityFactory.cpp | 19 ++-- .../base/InteractivityFactory.hpp | 2 +- src/interactivity/base/ServiceLocator.cpp | 13 ++- .../inc/IInteractivityFactory.hpp | 2 +- src/interactivity/inc/ServiceLocator.hpp | 2 +- src/terminal/adapter/conGetSet.hpp | 2 + src/tools/scratch/main.cpp | 88 +++++++++++-------- src/winconpty/winconpty.cpp | 44 ++++++++++ src/winconpty/winconpty.h | 2 + 29 files changed, 237 insertions(+), 46 deletions(-) diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 1d43f113ba5..7524bd68351 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -65,6 +65,8 @@ namespace winrt::TerminalApp::implementation void LoadSettings(); [[nodiscard]] Microsoft::Terminal::Settings::Model::CascadiaSettings GetSettings() const noexcept; + void SetOwnerHwnd(uint64_t owner) { _root->SetOwnerHwnd(owner); } + void Quit(); bool HasCommandlineArguments() const noexcept; diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 57e7a914e25..6752e8b14df 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -44,6 +44,8 @@ namespace TerminalApp // registered?" when it definitely is. void Create(); + void SetOwnerHwnd(UInt64 owner); + Boolean IsUwp(); void RunAsUwp(); Boolean IsElevated(); diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 630378a5d07..a1a95fa03d0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2410,6 +2410,9 @@ namespace winrt::TerminalApp::implementation // create here. // TermControl will copy the settings out of the settings passed to it. TermControl term{ settings.DefaultSettings(), settings.UnfocusedSettings(), connection }; + if (_hostingHwnd.has_value()) + term.OwningHwnd(_ownerHwnd); + // term.OwningHwnd(reinterpret_cast(_ownerHwnd)); return term; } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index a1867178590..e3f5dc277e9 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -63,6 +63,9 @@ namespace winrt::TerminalApp::implementation void Create(); + uint64_t _ownerHwnd{ 0 }; + void SetOwnerHwnd(uint64_t owner) { _ownerHwnd = owner; }; + bool ShouldUsePersistedLayout(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const; bool ShouldImmediatelyHandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const; void HandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index b4e5978440b..f25ae642b4a 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -296,6 +296,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation if (!_inPipe) { THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, PSEUDOCONSOLE_RESIZE_QUIRK | PSEUDOCONSOLE_WIN32_INPUT_MODE, &_inPipe, &_outPipe, &_hPC)); + THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast(_initialParentHwnd))); THROW_IF_FAILED(_LaunchAttachedClient()); } // But if it was an inbound handoff... attempt to synchronize the size of it with what our connection @@ -313,6 +314,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(_initialParentHwnd))); } _startTime = std::chrono::high_resolution_clock::now(); @@ -468,6 +470,20 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation } } + void ConptyConnection::ReparentWindow(const uint64_t newParent) + { + // If we haven't started connecting at all, TODO! + if (!_isStateAtOrBeyond(ConnectionState::Connecting)) + { + _initialParentHwnd = newParent; + } + // Otherwise, TODO! + else if (_isConnected()) + { + THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast(newParent))); + } + } + void ConptyConnection::Close() noexcept try { diff --git a/src/cascadia/TerminalConnection/ConptyConnection.h b/src/cascadia/TerminalConnection/ConptyConnection.h index 4089a944675..65037e922ee 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.h +++ b/src/cascadia/TerminalConnection/ConptyConnection.h @@ -35,6 +35,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation void Resize(uint32_t rows, uint32_t columns); void Close() noexcept; void ClearBuffer(); + void ReparentWindow(const uint64_t newParent); winrt::guid Guid() const noexcept; winrt::hstring Commandline() const; @@ -65,6 +66,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation uint32_t _initialRows{}; uint32_t _initialCols{}; + uint64_t _initialParentHwnd{ 0 }; hstring _commandline{}; hstring _startingDirectory{}; hstring _startingTitle{}; diff --git a/src/cascadia/TerminalConnection/ConptyConnection.idl b/src/cascadia/TerminalConnection/ConptyConnection.idl index 4c3df03ce63..7d495cb638c 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.idl +++ b/src/cascadia/TerminalConnection/ConptyConnection.idl @@ -13,6 +13,7 @@ namespace Microsoft.Terminal.TerminalConnection Guid Guid { get; }; String Commandline { get; }; void ClearBuffer(); + void ReparentWindow(UInt64 newParent); static event NewConnectionHandler NewConnection; static void StartInboundListener(); diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 27202a114e0..a86f9620647 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -262,6 +262,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation const auto height = vp.Height(); _connection.Resize(height, width); + if (auto conpty{ _connection.try_as() }) + { + conpty.ReparentWindow(_OwningHwnd); + } + // Override the default width and height to match the size of the swapChainPanel _settings->InitialCols(width); _settings->InitialRows(height); diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 2a86c2585cd..e4688a50c88 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -168,6 +168,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation void AdjustOpacity(const double opacity, const bool relative); + WINRT_PROPERTY(uint64_t, OwningHwnd, 0); + RUNTIME_SETTING(double, Opacity, _settings->Opacity()); RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic()); diff --git a/src/cascadia/TerminalControl/ICoreState.idl b/src/cascadia/TerminalControl/ICoreState.idl index ac9a2a3465c..fd11bda8f14 100644 --- a/src/cascadia/TerminalControl/ICoreState.idl +++ b/src/cascadia/TerminalControl/ICoreState.idl @@ -24,5 +24,8 @@ namespace Microsoft.Terminal.Control Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; }; Microsoft.Terminal.Core.Scheme ColorScheme { get; set; }; + + UInt64 OwningHwnd; + }; } diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index cf415b000c9..37edfe752f4 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -2772,4 +2772,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation } } + void TermControl::OwningHwnd(uint64_t owner) + { + _core.OwningHwnd(owner); + } + + uint64_t TermControl::OwningHwnd() + { + return _core.OwningHwnd(); + } + } diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 95aa82cdb92..512ab1476b6 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -59,6 +59,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); diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index f1380679c38..27a215e6f69 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -310,6 +310,7 @@ void AppHost::Initialize() if (auto withWindow{ _logic.try_as() }) { withWindow->Initialize(_window->GetHandle()); + _logic.SetOwnerHwnd(reinterpret_cast(_window->GetInteropHandle())); } if (_useNonClientArea) diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index cbd2509385c..5b334728cf5 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -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: diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index 53c00121d15..a39af64fc87 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -23,6 +23,7 @@ class IslandWindow : 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; diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index d480e135617..32e9c5033dc 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -67,6 +67,10 @@ void PtySignalInputThread::ConnectConsole() noexcept { _DoResizeWindow(*_earlyResize); } + if (_earlyReparent) + { + _DoSetWindowParent(*_earlyReparent); + } } // Method Description: @@ -119,6 +123,26 @@ void PtySignalInputThread::ConnectConsole() noexcept break; } + case PtySignal::SetParent: + { + SetParentData reparentMessage = { 0 }; + _GetData(&reparentMessage, sizeof(reparentMessage)); + + LockConsole(); + auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); + + // todo + // if (!_consoleConnected) + // { + // _earlyReparent = reparentMessage; + // } + // else + // { + _DoSetWindowParent(reparentMessage); + // } + + break; + } default: { THROW_HR(E_UNEXPECTED); @@ -147,6 +171,11 @@ void PtySignalInputThread::_DoClearBuffer() _pConApi->ClearBuffer(); } +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. diff --git a/src/host/PtySignalInputThread.hpp b/src/host/PtySignalInputThread.hpp index 74ffa8e022b..ea96e3342cc 100644 --- a/src/host/PtySignalInputThread.hpp +++ b/src/host/PtySignalInputThread.hpp @@ -41,6 +41,7 @@ namespace Microsoft::Console enum class PtySignal : unsigned short { ClearBuffer = 2, + SetParent = 3, ResizeWindow = 8 }; @@ -49,10 +50,15 @@ namespace Microsoft::Console unsigned short sx; unsigned short sy; }; + 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 _Shutdown(); @@ -61,6 +67,7 @@ namespace Microsoft::Console DWORD _dwThreadId; bool _consoleConnected; std::optional _earlyResize; + std::optional _earlyReparent; std::unique_ptr _pConApi; }; } diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index cbae4519159..72fdbbee641 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -892,3 +892,13 @@ void ConhostInternalGetSet::UpdateSoftFont(const gsl::span bitPa pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint); } } + +void ConhostInternalGetSet::ReparentWindow(const uint64_t handle) +{ + // This will initialize s_interactivityFactory for us. It will also + // convniently return 0 when we're on OneCore. + if (const auto psuedoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast(handle)) }) + { + LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast(handle))); + } +} diff --git a/src/host/outputStream.hpp b/src/host/outputStream.hpp index 458e1ab550f..75db5f59076 100644 --- a/src/host/outputStream.hpp +++ b/src/host/outputStream.hpp @@ -116,6 +116,8 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal:: const SIZE cellSize, const size_t centeringHint) override; + void ReparentWindow(const uint64_t handle); + private: void _modifyLines(const size_t count, const bool insert); diff --git a/src/inc/conpty-static.h b/src/inc/conpty-static.h index 052708a6bd5..8bba2750b56 100644 --- a/src/inc/conpty-static.h +++ b/src/inc/conpty-static.h @@ -24,6 +24,8 @@ HRESULT WINAPI ConptyResizePseudoConsole(HPCON hPC, COORD size); HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC); +HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newParent); + VOID WINAPI ConptyClosePseudoConsole(HPCON hPC); HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC); diff --git a/src/interactivity/base/InteractivityFactory.cpp b/src/interactivity/base/InteractivityFactory.cpp index 1442f4e9a00..89171c79b4a 100644 --- a/src/interactivity/base/InteractivityFactory.cpp +++ b/src/interactivity/base/InteractivityFactory.cpp @@ -334,12 +334,12 @@ using namespace Microsoft::Console::Interactivity; // - hwnd: Receives the value of the newly created window's HWND. // 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; NTSTATUS status = ApiDetector::DetectNtUserWindow(&level); - ; + if (NT_SUCCESS(status)) { try @@ -349,20 +349,24 @@ using namespace Microsoft::Console::Interactivity; switch (level) { case ApiLevel::Win32: + { pseudoClass.lpszClassName = PSEUDO_WINDOW_CLASS; pseudoClass.lpfnWndProc = DefWindowProc; RegisterClass(&pseudoClass); + + const auto windowStyle = (owner == HWND_DESKTOP) ? WS_OVERLAPPEDWINDOW : WS_CHILD; + // Attempt to create window hwnd = CreateWindowExW( 0, PSEUDO_WINDOW_CLASS, nullptr, - WS_CHILD, //WS_OVERLAPPEDWINDOW, + windowStyle, //WS_CHILD, //WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, - (HWND)0x00070C6A, //HWND_DESKTOP,// parent + owner /*(HWND)0x00070C6A*/ /*HWND_DESKTOP*/, // parent nullptr, nullptr, nullptr); @@ -371,8 +375,13 @@ using namespace Microsoft::Console::Interactivity; DWORD const gle = GetLastError(); status = NTSTATUS_FROM_WIN32(gle); } - break; + const auto awareness{GetThreadDpiAwarenessContext()}; + awareness; + SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + + break; + } #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: hwnd = 0; diff --git a/src/interactivity/base/InteractivityFactory.hpp b/src/interactivity/base/InteractivityFactory.hpp index bf08158343f..0a166669a69 100644 --- a/src/interactivity/base/InteractivityFactory.hpp +++ b/src/interactivity/base/InteractivityFactory.hpp @@ -27,6 +27,6 @@ namespace Microsoft::Console::Interactivity [[nodiscard]] NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr& provider); [[nodiscard]] NTSTATUS CreateInputServices(_Inout_ std::unique_ptr& services); - [[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd); + [[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd, const HWND owner); }; } diff --git a/src/interactivity/base/ServiceLocator.cpp b/src/interactivity/base/ServiceLocator.cpp index 49a89e3e81c..1a9e9236b65 100644 --- a/src/interactivity/base/ServiceLocator.cpp +++ b/src/interactivity/base/ServiceLocator.cpp @@ -302,7 +302,7 @@ Globals& ServiceLocator::LocateGlobals() // - // Return Value: // - a reference to the pseudoconsole window. -HWND ServiceLocator::LocatePseudoWindow() +HWND ServiceLocator::LocatePseudoWindow(const HWND owner) { NTSTATUS status = STATUS_SUCCESS; if (!s_pseudoWindowInitialized) @@ -315,7 +315,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); } s_pseudoWindowInitialized = true; @@ -324,7 +324,14 @@ HWND ServiceLocator::LocatePseudoWindow() return s_pseudoWindow.get(); } -#pragma endregion +// void ServiceLocator::ReparentPseudoHwnd(HWND newParent) +// { +// // This will initialize s_interactivityFactory for us. It will also convniently return 0 when we're on OneCore. +// if (const auto psuedoHwnd{ LocatePseudoWindow() }) +// { +// ::SetParent(psuedoHwnd, newParent); +// } +// } #pragma endregion diff --git a/src/interactivity/inc/IInteractivityFactory.hpp b/src/interactivity/inc/IInteractivityFactory.hpp index 4996f30d689..f27b88cfa18 100644 --- a/src/interactivity/inc/IInteractivityFactory.hpp +++ b/src/interactivity/inc/IInteractivityFactory.hpp @@ -42,7 +42,7 @@ namespace Microsoft::Console::Interactivity [[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr& provider) = 0; [[nodiscard]] virtual NTSTATUS CreateInputServices(_Inout_ std::unique_ptr& services) = 0; - [[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0; + [[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd, const HWND owner) = 0; }; inline IInteractivityFactory::~IInteractivityFactory() {} diff --git a/src/interactivity/inc/ServiceLocator.hpp b/src/interactivity/inc/ServiceLocator.hpp index cbcbdd8f0b0..f48ebfcf868 100644 --- a/src/interactivity/inc/ServiceLocator.hpp +++ b/src/interactivity/inc/ServiceLocator.hpp @@ -89,7 +89,7 @@ namespace Microsoft::Console::Interactivity static Globals& LocateGlobals(); - static HWND LocatePseudoWindow(); + static HWND LocatePseudoWindow(const HWND owner = 0/*HNWD_DESKTOP*/); protected: ServiceLocator(ServiceLocator const&) = delete; diff --git a/src/terminal/adapter/conGetSet.hpp b/src/terminal/adapter/conGetSet.hpp index 1cfe0d2613b..6dd127c2825 100644 --- a/src/terminal/adapter/conGetSet.hpp +++ b/src/terminal/adapter/conGetSet.hpp @@ -111,5 +111,7 @@ namespace Microsoft::Console::VirtualTerminal virtual void UpdateSoftFont(const gsl::span bitPattern, const SIZE cellSize, const size_t centeringHint) = 0; + + virtual void ReparentWindow(const uint64_t handle) = 0; }; } diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index 70dafac14b8..73eaa222557 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -57,11 +57,20 @@ HWND find_main_window(unsigned long process_id) static LRESULT __stdcall WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { + static bool gotKeyDown{ false }; switch (message) { case WM_DESTROY: PostQuitMessage(0); return 0; + + case WM_KEYDOWN: + gotKeyDown = true; + return 0; + case WM_KEYUP: + if (gotKeyDown) + DestroyWindow(window); + return 0; } return DefWindowProc(window, message, wparam, lparam); } @@ -71,44 +80,53 @@ int doTheWindowThing(HWND hwndToUseAsParent) const auto hInst{ GetModuleHandle(NULL) }; wprintf(fmt::format(L"Creating a Window, then a MessageBox, using {} as the parent HWND\n", reinterpret_cast(hwndToUseAsParent)).c_str()); - // Create the window. - HWND hwnd = CreateWindowEx( - 0, // Optional window styles. - CLASS_NAME, // Window class - L"Learn to Program Windows", // Window text - WS_OVERLAPPEDWINDOW, // Window style - - // Size and position - 200, - 200, - 200, - 200, - - hwndToUseAsParent, // Parent window - NULL, // Menu - hInst, // Instance handle - NULL // Additional application data - ); - - // wprintf(fmt::format(L"hwnd: {}\n", reinterpret_cast(hwnd)).c_str()); - - // const auto newHwnd{ find_main_window(pid) }; - // wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast(newHwnd)).c_str()); - - if (hwnd == NULL) - { + auto doWindowCreateLoop = [&](bool child) { + // Create the window. + HWND hwnd = CreateWindowEx( + 0, // Optional window styles. + CLASS_NAME, // Window class + L"Learn to Program Windows", // Window text + WS_OVERLAPPEDWINDOW | (child ? WS_CHILD : 0), // Window style + + // Size and position + 200, + 200, + 200, + 200, + + hwndToUseAsParent, // Parent window + NULL, // Menu + hInst, // Instance handle + NULL // Additional application data + ); + + // wprintf(fmt::format(L"hwnd: {}\n", reinterpret_cast(hwnd)).c_str()); + + // const auto newHwnd{ find_main_window(pid) }; + // wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast(newHwnd)).c_str()); + + if (hwnd == NULL) + { + return 0; + } + + ShowWindow(hwnd, SW_SHOW); + MSG msg = {}; + while (GetMessage(&msg, NULL, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + wprintf(fmt::format(L"window was closed\n").c_str()); return 0; - } + }; - ShowWindow(hwnd, SW_SHOW); - MSG msg = {}; - while (GetMessage(&msg, NULL, 0, 0) > 0) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } + wprintf(fmt::format(L"create an unowned window...\n").c_str()); + doWindowCreateLoop(false); - wprintf(fmt::format(L"window was closed\n").c_str()); + // wprintf(fmt::format(L"create a child window...\n").c_str()); + // doWindowCreateLoop(true); wprintf(fmt::format(L"Opening a messagebox...\n").c_str()); MessageBoxW(hwndToUseAsParent, L"foo", L"bar", MB_OK); diff --git a/src/winconpty/winconpty.cpp b/src/winconpty/winconpty.cpp index 7653ce6bd5c..2feae841ff7 100644 --- a/src/winconpty/winconpty.cpp +++ b/src/winconpty/winconpty.cpp @@ -252,6 +252,37 @@ HRESULT _ClearPseudoConsole(_In_ const PseudoConsole* const pPty) return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } +// Function Description: +// - TODO! +HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const HWND newParent) +{ + if (pPty == nullptr) + { + return E_INVALIDARG; + } + +#pragma pack(push, 1) + struct _signal + { + const unsigned short id; // = PTY_SIGNAL_RESIZE_WINDOW; + const uint64_t hwnd; // = reinterpret_cast(newParent); + } data{ PTY_SIGNAL_REPARENT_WINDOW, reinterpret_cast(newParent) }; +#pragma pack(pop) + + // unsigned short signalPacket[5]; + // signalPacket[0] = PTY_SIGNAL_RESIZE_WINDOW; + // // hwnd is a uint64_t. + // signalPacket[1] = size.X; + // signalPacket[2] = size.Y; + // signalPacket[3] = size.Y; + // signalPacket[4] = size.Y; + // static_assert(sizeof(data) == (10)); + // static_assert(sizeof(data) == (sizeof(unsigned short) + sizeof(HWND))); + + 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, @@ -423,6 +454,19 @@ extern "C" HRESULT WINAPI ConptyClearPseudoConsole(_In_ HPCON hPC) return hr; } +// Function Description: +// - TODO! +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 diff --git a/src/winconpty/winconpty.h b/src/winconpty/winconpty.h index f2a7ff429ee..32458634c15 100644 --- a/src/winconpty/winconpty.h +++ b/src/winconpty/winconpty.h @@ -18,6 +18,7 @@ typedef struct _PseudoConsole // These are not defined publicly, but are used for controlling the conpty via // the signal pipe. #define PTY_SIGNAL_CLEAR_WINDOW (2u) +#define PTY_SIGNAL_REPARENT_WINDOW (3u) #define PTY_SIGNAL_RESIZE_WINDOW (8u) // CreatePseudoConsole Flags @@ -36,6 +37,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); From cb2ad2b2855393b94decaa6d8301ffda07d5fd26 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 17 Feb 2022 17:03:34 -0600 Subject: [PATCH 04/15] fixed the message pump --- src/host/PtySignalInputThread.cpp | 16 ++++++++-------- src/host/PtySignalInputThread.hpp | 5 ++++- src/host/VtIo.cpp | 10 ++++++++++ src/tools/scratch/main.cpp | 15 ++++++++------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index 32e9c5033dc..3bb20c6fa68 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -132,14 +132,14 @@ void PtySignalInputThread::ConnectConsole() noexcept auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); // todo - // if (!_consoleConnected) - // { - // _earlyReparent = reparentMessage; - // } - // else - // { - _DoSetWindowParent(reparentMessage); - // } + if (!_consoleConnected) + { + _earlyReparent = reparentMessage; + } + else + { + _DoSetWindowParent(reparentMessage); + } break; } diff --git a/src/host/PtySignalInputThread.hpp b/src/host/PtySignalInputThread.hpp index ea96e3342cc..dbe4c192c39 100644 --- a/src/host/PtySignalInputThread.hpp +++ b/src/host/PtySignalInputThread.hpp @@ -37,6 +37,7 @@ namespace Microsoft::Console void ConnectConsole() noexcept; + private: enum class PtySignal : unsigned short { @@ -67,7 +68,9 @@ namespace Microsoft::Console DWORD _dwThreadId; bool _consoleConnected; std::optional _earlyResize; - std::optional _earlyReparent; std::unique_ptr _pConApi; + + public: + std::optional _earlyReparent; }; } diff --git a/src/host/VtIo.cpp b/src/host/VtIo.cpp index 5b482ecd185..788fe91d86c 100644 --- a/src/host/VtIo.cpp +++ b/src/host/VtIo.cpp @@ -254,6 +254,16 @@ 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 parent hwnd will + // cause us to get a dpi change as well, which we'll never deque and + // handle, effectively HANGING THE PARENT HWND. super bad. + // + // TODO! clean this up + if (_pPtySignalInputThread->_earlyReparent.has_value()) + { + ServiceLocator::LocatePseudoWindow(reinterpret_cast(_pPtySignalInputThread->_earlyReparent.value().handle)); + } // Let the signal thread know that the console is connected _pPtySignalInputThread->ConnectConsole(); } diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index 73eaa222557..ea831bd51be 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -78,7 +78,7 @@ static LRESULT __stdcall WndProc(HWND const window, UINT const message, WPARAM c int doTheWindowThing(HWND hwndToUseAsParent) { const auto hInst{ GetModuleHandle(NULL) }; - wprintf(fmt::format(L"Creating a Window, then a MessageBox, using {} as the parent HWND\n", reinterpret_cast(hwndToUseAsParent)).c_str()); + wprintf(fmt::format(L"=====Creating a Window, then a MessageBox, using {} as the parent HWND=====\n", reinterpret_cast(hwndToUseAsParent)).c_str()); auto doWindowCreateLoop = [&](bool child) { // Create the window. @@ -109,6 +109,7 @@ int doTheWindowThing(HWND hwndToUseAsParent) { return 0; } + wprintf(fmt::format(L" created window\n").c_str()); ShowWindow(hwnd, SW_SHOW); MSG msg = {}; @@ -118,19 +119,19 @@ int doTheWindowThing(HWND hwndToUseAsParent) DispatchMessage(&msg); } - wprintf(fmt::format(L"window was closed\n").c_str()); + wprintf(fmt::format(L" window was closed\n").c_str()); return 0; }; - wprintf(fmt::format(L"create an unowned window...\n").c_str()); + wprintf(fmt::format(L" create an unowned window...\n").c_str()); doWindowCreateLoop(false); - // wprintf(fmt::format(L"create a child window...\n").c_str()); - // doWindowCreateLoop(true); + wprintf(fmt::format(L" create a child window...\n").c_str()); + doWindowCreateLoop(true); - wprintf(fmt::format(L"Opening a messagebox...\n").c_str()); + wprintf(fmt::format(L" Opening a messagebox...\n").c_str()); MessageBoxW(hwndToUseAsParent, L"foo", L"bar", MB_OK); - wprintf(fmt::format(L"closed a messagebox\n").c_str()); + wprintf(fmt::format(L" closed a messagebox\n").c_str()); return 0; } From b2575819b459f369fb96d2f4a9683d340bf72c0a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 18 Feb 2022 07:03:19 -0600 Subject: [PATCH 05/15] okay there's a way to get the terminal handle with this. I want to try with the actual terminal hwnd too --- src/tools/scratch/main.cpp | 42 +++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index ea831bd51be..4097e2d8b67 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -135,18 +135,8 @@ int doTheWindowThing(HWND hwndToUseAsParent) return 0; } -// This wmain exists for help in writing scratch programs while debugging. -int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) +int createSomeWindows(const HWND& consolwHwnd) { - const auto pid{ GetCurrentProcessId() }; - const auto dumb{ GetConsoleWindow() }; - - wprintf(fmt::format(L"pid: {}\n", pid).c_str()); - wprintf(fmt::format(L"dumb: {}\n", reinterpret_cast(dumb)).c_str()); - - // const auto mainHwnd{ find_main_window(pid) }; - // wprintf(fmt::format(L"mainHwnd: {}\n", reinterpret_cast(mainHwnd)).c_str()); - WNDCLASS wc = {}; const auto hInst{ GetModuleHandle(NULL) }; wc.lpfnWndProc = WndProc; @@ -159,7 +149,35 @@ int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) doTheWindowThing(nullptr); wprintf(fmt::format(L"Now, with the console window handle.\n").c_str()); - doTheWindowThing(dumb); + doTheWindowThing(consolwHwnd); + + return 0; +} + +// This wmain exists for help in writing scratch programs while debugging. +int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) +{ + const auto pid{ GetCurrentProcessId() }; + const auto consoleWindow{ GetConsoleWindow() }; + // createSomeWindows(consoleWindow); + + wprintf(fmt::format(L"pid: {}\n", pid).c_str()); + + wprintf(fmt::format(L"consoleWindow: {0:#010x}\n", reinterpret_cast(consoleWindow)).c_str()); + + const auto mainHwnd{ find_main_window(pid) }; + wprintf(fmt::format(L"mainHwnd: {0:#010x}\n", reinterpret_cast(mainHwnd)).c_str()); + + const auto consoleParent{ GetParent(consoleWindow) }; + wprintf(fmt::format(L"parent: {0:#010x}\n", reinterpret_cast(consoleParent)).c_str()); + const auto consoleOwner{ GetWindow(consoleWindow, GW_OWNER) }; + wprintf(fmt::format(L"owner: {0:#010x}\n", reinterpret_cast(consoleOwner)).c_str()); + const auto consoleAncestor_PARENT{ GetAncestor(consoleWindow, GA_PARENT) }; + const auto consoleAncestor_ROOT{ GetAncestor(consoleWindow, GA_ROOT) }; + const auto consoleAncestor_ROOTOWNER{ GetAncestor(consoleWindow, GA_ROOTOWNER) }; + wprintf(fmt::format(L"Ancestor_PARENT: {0:#010x}\n", reinterpret_cast(consoleAncestor_PARENT)).c_str()); + wprintf(fmt::format(L"Ancestor_ROOT: {0:#010x}\n", reinterpret_cast(consoleAncestor_ROOT)).c_str()); + wprintf(fmt::format(L"Ancestor_ROOTOWNER: {0:#010x}\n", reinterpret_cast(consoleAncestor_ROOTOWNER)).c_str()); return 0; } From 2009147c9df585b6e2b5076aacb0ef072aa0aab0 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 18 Feb 2022 09:41:04 -0600 Subject: [PATCH 06/15] a consistent way of getting the console or terminal hwnd? inconceivable! --- src/cascadia/WindowsTerminal/AppHost.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 27a215e6f69..490639da39e 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -310,7 +310,8 @@ void AppHost::Initialize() if (auto withWindow{ _logic.try_as() }) { withWindow->Initialize(_window->GetHandle()); - _logic.SetOwnerHwnd(reinterpret_cast(_window->GetInteropHandle())); + // _logic.SetOwnerHwnd(reinterpret_cast(_window->GetInteropHandle())); + _logic.SetOwnerHwnd(reinterpret_cast(_window->GetHandle())); } if (_useNonClientArea) From 669b1e2609c27575fb72d07e4eb1d2a55ebc4b36 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 18 Feb 2022 10:55:38 -0600 Subject: [PATCH 07/15] spell, fix test mock --- .github/actions/spelling/allow/apis.txt | 1 + src/host/outputStream.cpp | 2 +- src/interactivity/base/ServiceLocator.cpp | 2 +- src/interactivity/inc/ServiceLocator.hpp | 2 +- src/terminal/adapter/ut_adapter/adapterTest.cpp | 5 +++++ src/tools/scratch/main.cpp | 8 ++++---- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt index 13d32233b58..930f3eb68e5 100644 --- a/.github/actions/spelling/allow/apis.txt +++ b/.github/actions/spelling/allow/apis.txt @@ -143,6 +143,7 @@ REGCLS RETURNCMD rfind roundf +ROOTOWNER RSHIFT SACL schandle diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index 72fdbbee641..b877b6d4d6b 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -896,7 +896,7 @@ void ConhostInternalGetSet::UpdateSoftFont(const gsl::span bitPa void ConhostInternalGetSet::ReparentWindow(const uint64_t handle) { // This will initialize s_interactivityFactory for us. It will also - // convniently return 0 when we're on OneCore. + // conveniently return 0 when we're on OneCore. if (const auto psuedoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast(handle)) }) { LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast(handle))); diff --git a/src/interactivity/base/ServiceLocator.cpp b/src/interactivity/base/ServiceLocator.cpp index 1a9e9236b65..2d64f579cd3 100644 --- a/src/interactivity/base/ServiceLocator.cpp +++ b/src/interactivity/base/ServiceLocator.cpp @@ -326,7 +326,7 @@ HWND ServiceLocator::LocatePseudoWindow(const HWND owner) // void ServiceLocator::ReparentPseudoHwnd(HWND newParent) // { -// // This will initialize s_interactivityFactory for us. It will also convniently return 0 when we're on OneCore. +// // This will initialize s_interactivityFactory for us. It will also conveniently return 0 when we're on OneCore. // if (const auto psuedoHwnd{ LocatePseudoWindow() }) // { // ::SetParent(psuedoHwnd, newParent); diff --git a/src/interactivity/inc/ServiceLocator.hpp b/src/interactivity/inc/ServiceLocator.hpp index f48ebfcf868..01c67517258 100644 --- a/src/interactivity/inc/ServiceLocator.hpp +++ b/src/interactivity/inc/ServiceLocator.hpp @@ -89,7 +89,7 @@ namespace Microsoft::Console::Interactivity static Globals& LocateGlobals(); - static HWND LocatePseudoWindow(const HWND owner = 0/*HNWD_DESKTOP*/); + static HWND LocatePseudoWindow(const HWND owner = 0 /*HWND_DESKTOP*/); protected: ServiceLocator(ServiceLocator const&) = delete; diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp index f102b168e87..42e461c9c4f 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -422,6 +422,11 @@ class TestGetSet final : public ConGetSet VERIFY_ARE_EQUAL(_expectedCellSize.cy, cellSize.cy); } + void ReparentWindow(const uint64_t /*handle*/) + { + Log::Comment(L"UpdateSoftFont MOCK called..."); + } + void PrepData() { PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter. diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index 4097e2d8b67..029b50f140f 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -129,13 +129,13 @@ int doTheWindowThing(HWND hwndToUseAsParent) wprintf(fmt::format(L" create a child window...\n").c_str()); doWindowCreateLoop(true); - wprintf(fmt::format(L" Opening a messagebox...\n").c_str()); + wprintf(fmt::format(L" Opening a MessageBoxW...\n").c_str()); MessageBoxW(hwndToUseAsParent, L"foo", L"bar", MB_OK); - wprintf(fmt::format(L" closed a messagebox\n").c_str()); + wprintf(fmt::format(L" closed a MessageBoxW\n").c_str()); return 0; } -int createSomeWindows(const HWND& consolwHwnd) +int createSomeWindows(const HWND& consoleHwnd) { WNDCLASS wc = {}; const auto hInst{ GetModuleHandle(NULL) }; @@ -149,7 +149,7 @@ int createSomeWindows(const HWND& consolwHwnd) doTheWindowThing(nullptr); wprintf(fmt::format(L"Now, with the console window handle.\n").c_str()); - doTheWindowThing(consolwHwnd); + doTheWindowThing(consoleHwnd); return 0; } From 5d96691b01a07b0011791f120725fbc068ffdf3b Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 18 Feb 2022 10:58:03 -0600 Subject: [PATCH 08/15] thanks for nothing VS --- src/cascadia/TerminalApp/TerminalPage.cpp | 2 +- src/host/PtySignalInputThread.hpp | 3 +-- src/interactivity/base/InteractivityFactory.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index a1a95fa03d0..20d2ee576c0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -2412,7 +2412,7 @@ namespace winrt::TerminalApp::implementation TermControl term{ settings.DefaultSettings(), settings.UnfocusedSettings(), connection }; if (_hostingHwnd.has_value()) term.OwningHwnd(_ownerHwnd); - // term.OwningHwnd(reinterpret_cast(_ownerHwnd)); + // term.OwningHwnd(reinterpret_cast(_ownerHwnd)); return term; } diff --git a/src/host/PtySignalInputThread.hpp b/src/host/PtySignalInputThread.hpp index dbe4c192c39..71d1ed27c83 100644 --- a/src/host/PtySignalInputThread.hpp +++ b/src/host/PtySignalInputThread.hpp @@ -37,7 +37,6 @@ namespace Microsoft::Console void ConnectConsole() noexcept; - private: enum class PtySignal : unsigned short { @@ -70,7 +69,7 @@ namespace Microsoft::Console std::optional _earlyResize; std::unique_ptr _pConApi; - public: + public: std::optional _earlyReparent; }; } diff --git a/src/interactivity/base/InteractivityFactory.cpp b/src/interactivity/base/InteractivityFactory.cpp index 89171c79b4a..b1733f14c59 100644 --- a/src/interactivity/base/InteractivityFactory.cpp +++ b/src/interactivity/base/InteractivityFactory.cpp @@ -376,7 +376,7 @@ using namespace Microsoft::Console::Interactivity; status = NTSTATUS_FROM_WIN32(gle); } - const auto awareness{GetThreadDpiAwarenessContext()}; + const auto awareness{ GetThreadDpiAwarenessContext() }; awareness; SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); From 23b6fee1f0b1722a9f081e52b8f47eea45a0f709 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 25 Feb 2022 10:49:11 -0600 Subject: [PATCH 09/15] this was a test that Evan wanted me to try. seemed to work okay, but it's not validated with WAM --- .../base/InteractivityFactory.cpp | 9 ++-- src/tools/scratch/main.cpp | 41 +++++++++++++++++-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/interactivity/base/InteractivityFactory.cpp b/src/interactivity/base/InteractivityFactory.cpp index b1733f14c59..08fa893a434 100644 --- a/src/interactivity/base/InteractivityFactory.cpp +++ b/src/interactivity/base/InteractivityFactory.cpp @@ -354,7 +354,8 @@ using namespace Microsoft::Console::Interactivity; pseudoClass.lpfnWndProc = DefWindowProc; RegisterClass(&pseudoClass); - const auto windowStyle = (owner == HWND_DESKTOP) ? WS_OVERLAPPEDWINDOW : WS_CHILD; + // const auto windowStyle = (owner == HWND_DESKTOP) ? WS_OVERLAPPEDWINDOW : WS_CHILD; + const auto windowStyle = WS_OVERLAPPEDWINDOW; // Attempt to create window hwnd = CreateWindowExW( @@ -376,9 +377,9 @@ using namespace Microsoft::Console::Interactivity; status = NTSTATUS_FROM_WIN32(gle); } - const auto awareness{ GetThreadDpiAwarenessContext() }; - awareness; - SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + // const auto awareness{ GetThreadDpiAwarenessContext() }; + // awareness; + // SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); break; } diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index 029b50f140f..26bcbec1acd 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -154,15 +154,12 @@ int createSomeWindows(const HWND& consoleHwnd) return 0; } -// This wmain exists for help in writing scratch programs while debugging. -int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) +int doDefaultOutput() { const auto pid{ GetCurrentProcessId() }; const auto consoleWindow{ GetConsoleWindow() }; - // createSomeWindows(consoleWindow); wprintf(fmt::format(L"pid: {}\n", pid).c_str()); - wprintf(fmt::format(L"consoleWindow: {0:#010x}\n", reinterpret_cast(consoleWindow)).c_str()); const auto mainHwnd{ find_main_window(pid) }; @@ -181,3 +178,39 @@ int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) return 0; } + +// This wmain exists for help in writing scratch programs while debugging. +int __cdecl wmain(int argc, WCHAR* argv[]) +{ + doDefaultOutput(); + + const auto consoleWindow{ GetConsoleWindow() }; + + if (argc <= 1) + { + return 0; + } + + HWND target = consoleWindow; + std::wstring arg{ argv[1] }; + if (arg == L"--parent" && argc > 2) + { + target = GetAncestor(consoleWindow, GA_ROOT); + arg = argv[2]; + } + + if (arg == L"messagebox") + { + MessageBoxW(target, L"foo", L"bar", MB_OK); + } + else if (arg == L"windows") + { + createSomeWindows(target); + } + else if (arg == L"hide") + { + ShowWindow(target, SW_HIDE); + } + + return 0; +} From cf65085faadc846d9911a6a64608fe5a40a7b5f4 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 31 Mar 2022 15:03:01 -0500 Subject: [PATCH 10/15] cleanup everywhere --- src/cascadia/TerminalApp/AppLogic.cpp | 1 + src/cascadia/TerminalApp/AppLogic.h | 2 - src/cascadia/TerminalApp/AppLogic.idl | 2 - src/cascadia/TerminalApp/TerminalPage.cpp | 29 +++++++++++- src/cascadia/TerminalApp/TerminalPage.h | 3 -- .../TerminalConnection/ConptyConnection.cpp | 12 +++-- src/cascadia/TerminalControl/ControlCore.cpp | 7 ++- src/cascadia/TerminalControl/ControlCore.h | 3 ++ src/cascadia/WindowsTerminal/AppHost.cpp | 2 - src/host/PtySignalInputThread.cpp | 31 ++++++++++++- src/host/VtIo.cpp | 12 ++--- src/host/outputStream.cpp | 4 ++ .../base/InteractivityFactory.cpp | 44 +++++++++++-------- src/interactivity/base/ServiceLocator.cpp | 12 +---- .../adapter/ut_adapter/adapterTest.cpp | 2 +- src/winconpty/winconpty.cpp | 32 ++++++++------ 16 files changed, 129 insertions(+), 69 deletions(-) diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index fe6636a4f93..af1bb4c3ce2 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -1641,4 +1641,5 @@ namespace winrt::TerminalApp::implementation { return _settings.GlobalSettings().ShowTitleInTitlebar(); } + } diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 41eecabd5ce..582866704b4 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -65,8 +65,6 @@ namespace winrt::TerminalApp::implementation void LoadSettings(); [[nodiscard]] Microsoft::Terminal::Settings::Model::CascadiaSettings GetSettings() const noexcept; - void SetOwnerHwnd(uint64_t owner) { _root->SetOwnerHwnd(owner); } - void Quit(); bool HasCommandlineArguments() const noexcept; diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 7c99028ac8e..df0f7b3cd47 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -46,8 +46,6 @@ namespace TerminalApp // registered?" when it definitely is. void Create(); - void SetOwnerHwnd(UInt64 owner); - Boolean IsUwp(); void RunAsUwp(); Boolean IsElevated(); diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index e542fa88d8d..f1fa3e8f095 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -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; @@ -2424,9 +2430,11 @@ namespace winrt::TerminalApp::implementation // create here. // TermControl will copy the settings out of the settings passed to it. TermControl term{ settings.DefaultSettings(), settings.UnfocusedSettings(), connection }; + if (_hostingHwnd.has_value()) - term.OwningHwnd(_ownerHwnd); - // term.OwningHwnd(reinterpret_cast(_ownerHwnd)); + { + term.OwningHwnd(reinterpret_cast(*_hostingHwnd)); + } return term; } @@ -3892,4 +3900,21 @@ namespace winrt::TerminalApp::implementation applicationState.DismissedMessages(std::move(messages)); } + // Method Description: + // - Used to tell the Terminal what the root HWND is for the application. + // 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. + // Arguments: + // - owner: the HWND that owns this window. + // Return Value: + // - + void TerminalPage::SetOwnerHwnd(uint64_t owner) + { + _ownerHwnd = owner; + } + } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 8eec74590d4..2e48d9db883 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -63,9 +63,6 @@ namespace winrt::TerminalApp::implementation void Create(); - uint64_t _ownerHwnd{ 0 }; - void SetOwnerHwnd(uint64_t owner) { _ownerHwnd = owner; }; - bool ShouldUsePersistedLayout(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const; bool ShouldImmediatelyHandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const; void HandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings); diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index a3666c959ad..c7677d288d5 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -310,7 +310,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation } THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, flags, &_inPipe, &_outPipe, &_hPC)); - THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast(_initialParentHwnd))); + + if (_initialParentHwnd != 0) + { + THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast(_initialParentHwnd))); + } THROW_IF_FAILED(_LaunchAttachedClient()); } @@ -487,12 +491,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation void ConptyConnection::ReparentWindow(const uint64_t newParent) { - // If we haven't started connecting at all, TODO! + // If we haven't started connecting at all, stash this HWND to use once we have started. if (!_isStateAtOrBeyond(ConnectionState::Connecting)) { _initialParentHwnd = newParent; } - // Otherwise, TODO! + // 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(newParent))); diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index a4a21f39dc7..05d022ef254 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -262,9 +262,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation const auto height = vp.Height(); _connection.Resize(height, width); - if (auto conpty{ _connection.try_as() }) + if (_OwningHwnd != 0) { - conpty.ReparentWindow(_OwningHwnd); + if (auto conpty{ _connection.try_as() }) + { + conpty.ReparentWindow(_OwningHwnd); + } } // Override the default width and height to match the size of the swapChainPanel diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 42e22b38521..592dc76aa46 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -168,6 +168,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation void AdjustOpacity(const double opacity, const bool relative); + // 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()); diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index c539284ff79..a12f1f1ca6a 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -335,8 +335,6 @@ void AppHost::Initialize() if (auto withWindow{ _logic.try_as() }) { withWindow->Initialize(_window->GetHandle()); - // _logic.SetOwnerHwnd(reinterpret_cast(_window->GetInteropHandle())); - _logic.SetOwnerHwnd(reinterpret_cast(_window->GetHandle())); } if (_useNonClientArea) diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index 3bb20c6fa68..482ba93f89c 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -131,7 +131,9 @@ void PtySignalInputThread::ConnectConsole() noexcept LockConsole(); auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); - // todo + // 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; @@ -171,11 +173,38 @@ void PtySignalInputThread::_DoClearBuffer() _pConApi->ClearBuffer(); } +// Method Description: +// - Update the owner of the pseudo-window we're using for the conpty HWND. This +// allows to mark the psuedoconsole 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: +// - void PtySignalInputThread::_DoSetWindowParent(const SetParentData& data) { _pConApi->ReparentWindow(data.handle); } +// Method Description: +// - If we were given a owner HWND, then manually start the pseudo window now. +// 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: +// - +// Return Value: +// - +void PtySignalInputThread::StartPseudoWindowIfNeeded() +{ + if (_earlyReparent.has_value()) + { + ServiceLocator::LocatePseudoWindow(reinterpret_cast(_earlyReparent.value().handle)); + } +} + // Method Description: // - Retrieves bytes from the file stream and exits or throws errors should the pipe state // be compromised. diff --git a/src/host/VtIo.cpp b/src/host/VtIo.cpp index 2b72b6712bd..040c655141d 100644 --- a/src/host/VtIo.cpp +++ b/src/host/VtIo.cpp @@ -297,15 +297,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 parent hwnd will + // 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 PARENT HWND. super bad. - // - // TODO! clean this up - if (_pPtySignalInputThread->_earlyReparent.has_value()) - { - ServiceLocator::LocatePseudoWindow(reinterpret_cast(_pPtySignalInputThread->_earlyReparent.value().handle)); - } + // handle, effectively HANGING THE OWNER HWND. + _pPtySignalInputThread->StartPseudoWindowIfNeeded(); + // Let the signal thread know that the console is connected _pPtySignalInputThread->ConnectConsole(); } diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index 443ce554f15..6a4244926e6 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -897,6 +897,10 @@ 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(handle)) }) { LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast(handle))); diff --git a/src/interactivity/base/InteractivityFactory.cpp b/src/interactivity/base/InteractivityFactory.cpp index b7a4dead945..59877533bdf 100644 --- a/src/interactivity/base/InteractivityFactory.cpp +++ b/src/interactivity/base/InteractivityFactory.cpp @@ -289,6 +289,7 @@ 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, const HWND owner) @@ -311,33 +312,38 @@ using namespace Microsoft::Console::Interactivity; pseudoClass.lpfnWndProc = DefWindowProc; RegisterClass(&pseudoClass); - // const auto windowStyle = (owner == HWND_DESKTOP) ? WS_OVERLAPPEDWINDOW : WS_CHILD; + // When merging with #12515, we're going to need to adjust these styles. + // + // Note that because we're not specifing 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, whild owned windows are still + // relative to the desktop. (there are other subtlties 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; - // Attempt to create window - hwnd = CreateWindowExW( - 0, - PSEUDO_WINDOW_CLASS, - nullptr, - windowStyle, //WS_CHILD, //WS_OVERLAPPEDWINDOW, - 0, - 0, - 0, - 0, - owner /*(HWND)0x00070C6A*/ /*HWND_DESKTOP*/, // parent - nullptr, - nullptr, - nullptr); + // Attempt to create window. + hwnd = CreateWindowExW(0, + PSEUDO_WINDOW_CLASS, + nullptr, + windowStyle, + 0, + 0, + 0, + 0, + owner, + nullptr, + nullptr, + nullptr); + if (hwnd == nullptr) { DWORD const gle = GetLastError(); status = NTSTATUS_FROM_WIN32(gle); } - // const auto awareness{ GetThreadDpiAwarenessContext() }; - // awareness; - // SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - break; } #ifdef BUILD_ONECORE_INTERACTIVITY diff --git a/src/interactivity/base/ServiceLocator.cpp b/src/interactivity/base/ServiceLocator.cpp index f6f14df16c6..ee86679a1f2 100644 --- a/src/interactivity/base/ServiceLocator.cpp +++ b/src/interactivity/base/ServiceLocator.cpp @@ -288,7 +288,8 @@ Globals& ServiceLocator::LocateGlobals() // Method Description: // - Retrieves the pseudo console window, or attempts to instantiate one. // Arguments: -// - +// - 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(const HWND owner) @@ -313,15 +314,6 @@ HWND ServiceLocator::LocatePseudoWindow(const HWND owner) return s_pseudoWindow.get(); } -// void ServiceLocator::ReparentPseudoHwnd(HWND newParent) -// { -// // This will initialize s_interactivityFactory for us. It will also conveniently return 0 when we're on OneCore. -// if (const auto psuedoHwnd{ LocatePseudoWindow() }) -// { -// ::SetParent(psuedoHwnd, newParent); -// } -// } - #pragma endregion #pragma region Private Methods diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp index 414486ab7a4..5fb239682a4 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -424,7 +424,7 @@ class TestGetSet final : public ConGetSet void ReparentWindow(const uint64_t /*handle*/) { - Log::Comment(L"UpdateSoftFont MOCK called..."); + Log::Comment(L"ReparentWindow MOCK called..."); } void PrepData() diff --git a/src/winconpty/winconpty.cpp b/src/winconpty/winconpty.cpp index 885e55fa2a9..e5331c73918 100644 --- a/src/winconpty/winconpty.cpp +++ b/src/winconpty/winconpty.cpp @@ -255,7 +255,16 @@ HRESULT _ClearPseudoConsole(_In_ const PseudoConsole* const pPty) } // Function Description: -// - TODO! +// - 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. HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const HWND newParent) { if (pPty == nullptr) @@ -263,24 +272,15 @@ HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const 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; // = PTY_SIGNAL_RESIZE_WINDOW; - const uint64_t hwnd; // = reinterpret_cast(newParent); + const unsigned short id; + const uint64_t hwnd; } data{ PTY_SIGNAL_REPARENT_WINDOW, reinterpret_cast(newParent) }; #pragma pack(pop) - // unsigned short signalPacket[5]; - // signalPacket[0] = PTY_SIGNAL_RESIZE_WINDOW; - // // hwnd is a uint64_t. - // signalPacket[1] = size.X; - // signalPacket[2] = size.Y; - // signalPacket[3] = size.Y; - // signalPacket[4] = size.Y; - // static_assert(sizeof(data) == (10)); - // static_assert(sizeof(data) == (sizeof(unsigned short) + sizeof(HWND))); - const BOOL fSuccess = WriteFile(pPty->hSignal, &data, sizeof(data), nullptr, nullptr); return fSuccess ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } @@ -457,7 +457,11 @@ extern "C" HRESULT WINAPI ConptyClearPseudoConsole(_In_ HPCON hPC) } // Function Description: -// - TODO! +// - 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; From 659d752c3f11eeb0c3d593a123dcd0392a79c731 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 31 Mar 2022 15:03:29 -0500 Subject: [PATCH 11/15] revert this guy --- src/tools/scratch/main.cpp | 208 +------------------------------------ 1 file changed, 1 insertion(+), 207 deletions(-) diff --git a/src/tools/scratch/main.cpp b/src/tools/scratch/main.cpp index 26bcbec1acd..c6f9cc901a2 100644 --- a/src/tools/scratch/main.cpp +++ b/src/tools/scratch/main.cpp @@ -1,216 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -#include "../../inc/LibraryIncludes.h" #include -// Register the window class. -const wchar_t CLASS_NAME[] = L"Sample Window Class"; - -struct handle_data -{ - unsigned long process_id; - HWND window_handle; -}; - -BOOL is_main_window(HWND handle) -{ - auto owner{ GetWindow(handle, GW_OWNER) }; - // wprintf(fmt::format(L"\t\towner: {}\n", reinterpret_cast(owner)).c_str()); - return owner == (HWND)0 && IsWindowVisible(handle); -} - -BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam) -{ - // wprintf(fmt::format(L"enum_windows_callback\n").c_str()); - handle_data& data = *(handle_data*)lParam; - unsigned long process_id = 0; - GetWindowThreadProcessId(handle, &process_id); - const bool pidDidntMatch{ data.process_id != process_id }; - // wprintf(fmt::format(L"\tpidDidntMatch: {}\n", pidDidntMatch).c_str()); - const bool wasntMainWindow{ !is_main_window(handle) }; - // wprintf(fmt::format(L"\twasntMainWindow: {}\n", wasntMainWindow).c_str()); - if (pidDidntMatch || wasntMainWindow) - { - return TRUE; - } - - wprintf(fmt::format(L"\tpidDidntMatch: {}\n", pidDidntMatch).c_str()); - wprintf(fmt::format(L"\twasntMainWindow: {}\n", wasntMainWindow).c_str()); - - auto owner{ GetWindow(handle, GW_OWNER) }; - wprintf(fmt::format(L"\t\thandle: {}\n", reinterpret_cast(handle)).c_str()); - wprintf(fmt::format(L"\t\towner: {}\n", reinterpret_cast(owner)).c_str()); - - data.window_handle = handle; - return FALSE; -} - -HWND find_main_window(unsigned long process_id) -{ - handle_data data; - data.process_id = process_id; - data.window_handle = 0; - EnumWindows(enum_windows_callback, (LPARAM)&data); - return data.window_handle; -} - -static LRESULT __stdcall WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept -{ - static bool gotKeyDown{ false }; - switch (message) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_KEYDOWN: - gotKeyDown = true; - return 0; - case WM_KEYUP: - if (gotKeyDown) - DestroyWindow(window); - return 0; - } - return DefWindowProc(window, message, wparam, lparam); -} - -int doTheWindowThing(HWND hwndToUseAsParent) -{ - const auto hInst{ GetModuleHandle(NULL) }; - wprintf(fmt::format(L"=====Creating a Window, then a MessageBox, using {} as the parent HWND=====\n", reinterpret_cast(hwndToUseAsParent)).c_str()); - - auto doWindowCreateLoop = [&](bool child) { - // Create the window. - HWND hwnd = CreateWindowEx( - 0, // Optional window styles. - CLASS_NAME, // Window class - L"Learn to Program Windows", // Window text - WS_OVERLAPPEDWINDOW | (child ? WS_CHILD : 0), // Window style - - // Size and position - 200, - 200, - 200, - 200, - - hwndToUseAsParent, // Parent window - NULL, // Menu - hInst, // Instance handle - NULL // Additional application data - ); - - // wprintf(fmt::format(L"hwnd: {}\n", reinterpret_cast(hwnd)).c_str()); - - // const auto newHwnd{ find_main_window(pid) }; - // wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast(newHwnd)).c_str()); - - if (hwnd == NULL) - { - return 0; - } - wprintf(fmt::format(L" created window\n").c_str()); - - ShowWindow(hwnd, SW_SHOW); - MSG msg = {}; - while (GetMessage(&msg, NULL, 0, 0) > 0) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - wprintf(fmt::format(L" window was closed\n").c_str()); - return 0; - }; - - wprintf(fmt::format(L" create an unowned window...\n").c_str()); - doWindowCreateLoop(false); - - wprintf(fmt::format(L" create a child window...\n").c_str()); - doWindowCreateLoop(true); - - wprintf(fmt::format(L" Opening a MessageBoxW...\n").c_str()); - MessageBoxW(hwndToUseAsParent, L"foo", L"bar", MB_OK); - wprintf(fmt::format(L" closed a MessageBoxW\n").c_str()); - return 0; -} - -int createSomeWindows(const HWND& consoleHwnd) -{ - WNDCLASS wc = {}; - const auto hInst{ GetModuleHandle(NULL) }; - wc.lpfnWndProc = WndProc; - wc.hInstance = hInst; - wc.lpszClassName = CLASS_NAME; - - RegisterClass(&wc); - - wprintf(fmt::format(L"Make some windows, using NULL as the parent.\n").c_str()); - - doTheWindowThing(nullptr); - wprintf(fmt::format(L"Now, with the console window handle.\n").c_str()); - doTheWindowThing(consoleHwnd); - - return 0; -} - -int doDefaultOutput() -{ - const auto pid{ GetCurrentProcessId() }; - const auto consoleWindow{ GetConsoleWindow() }; - - wprintf(fmt::format(L"pid: {}\n", pid).c_str()); - wprintf(fmt::format(L"consoleWindow: {0:#010x}\n", reinterpret_cast(consoleWindow)).c_str()); - - const auto mainHwnd{ find_main_window(pid) }; - wprintf(fmt::format(L"mainHwnd: {0:#010x}\n", reinterpret_cast(mainHwnd)).c_str()); - - const auto consoleParent{ GetParent(consoleWindow) }; - wprintf(fmt::format(L"parent: {0:#010x}\n", reinterpret_cast(consoleParent)).c_str()); - const auto consoleOwner{ GetWindow(consoleWindow, GW_OWNER) }; - wprintf(fmt::format(L"owner: {0:#010x}\n", reinterpret_cast(consoleOwner)).c_str()); - const auto consoleAncestor_PARENT{ GetAncestor(consoleWindow, GA_PARENT) }; - const auto consoleAncestor_ROOT{ GetAncestor(consoleWindow, GA_ROOT) }; - const auto consoleAncestor_ROOTOWNER{ GetAncestor(consoleWindow, GA_ROOTOWNER) }; - wprintf(fmt::format(L"Ancestor_PARENT: {0:#010x}\n", reinterpret_cast(consoleAncestor_PARENT)).c_str()); - wprintf(fmt::format(L"Ancestor_ROOT: {0:#010x}\n", reinterpret_cast(consoleAncestor_ROOT)).c_str()); - wprintf(fmt::format(L"Ancestor_ROOTOWNER: {0:#010x}\n", reinterpret_cast(consoleAncestor_ROOTOWNER)).c_str()); - - return 0; -} - // This wmain exists for help in writing scratch programs while debugging. -int __cdecl wmain(int argc, WCHAR* argv[]) +int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) { - doDefaultOutput(); - - const auto consoleWindow{ GetConsoleWindow() }; - - if (argc <= 1) - { - return 0; - } - - HWND target = consoleWindow; - std::wstring arg{ argv[1] }; - if (arg == L"--parent" && argc > 2) - { - target = GetAncestor(consoleWindow, GA_ROOT); - arg = argv[2]; - } - - if (arg == L"messagebox") - { - MessageBoxW(target, L"foo", L"bar", MB_OK); - } - else if (arg == L"windows") - { - createSomeWindows(target); - } - else if (arg == L"hide") - { - ShowWindow(target, SW_HIDE); - } - return 0; } From 4edeec353370711c2c984ef2f0f5e7288c25615f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 31 Mar 2022 15:25:07 -0500 Subject: [PATCH 12/15] clean, finally --- src/cascadia/TerminalApp/TerminalPage.cpp | 17 ----------------- src/host/PtySignalInputThread.hpp | 1 + 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index f1fa3e8f095..4d53c1ae640 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3900,21 +3900,4 @@ namespace winrt::TerminalApp::implementation applicationState.DismissedMessages(std::move(messages)); } - // Method Description: - // - Used to tell the Terminal what the root HWND is for the application. - // 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. - // Arguments: - // - owner: the HWND that owns this window. - // Return Value: - // - - void TerminalPage::SetOwnerHwnd(uint64_t owner) - { - _ownerHwnd = owner; - } - } diff --git a/src/host/PtySignalInputThread.hpp b/src/host/PtySignalInputThread.hpp index 71d1ed27c83..499c158aa06 100644 --- a/src/host/PtySignalInputThread.hpp +++ b/src/host/PtySignalInputThread.hpp @@ -36,6 +36,7 @@ namespace Microsoft::Console PtySignalInputThread& operator=(const PtySignalInputThread&) = delete; void ConnectConsole() noexcept; + void StartPseudoWindowIfNeeded(); private: enum class PtySignal : unsigned short From 000cb83b4b5d63d9871fb051b686d8d9730f879a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 31 Mar 2022 16:10:43 -0500 Subject: [PATCH 13/15] spellcheck and auditmode, my nemis...ese? nemisises? --- src/host/PtySignalInputThread.cpp | 2 +- src/interactivity/base/InteractivityFactory.cpp | 6 +++--- src/winconpty/winconpty.cpp | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index 482ba93f89c..5e40983a71d 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -175,7 +175,7 @@ void PtySignalInputThread::_DoClearBuffer() // Method Description: // - Update the owner of the pseudo-window we're using for the conpty HWND. This -// allows to mark the psuedoconsole windows as "owner" by the terminal HWND +// allows to mark the pseudoconsole windows as "owner" by the terminal HWND // that's actually hosting them. // - Refer to GH#2988 // Arguments: diff --git a/src/interactivity/base/InteractivityFactory.cpp b/src/interactivity/base/InteractivityFactory.cpp index 59877533bdf..810f41d44ef 100644 --- a/src/interactivity/base/InteractivityFactory.cpp +++ b/src/interactivity/base/InteractivityFactory.cpp @@ -314,11 +314,11 @@ using namespace Microsoft::Console::Interactivity; // When merging with #12515, we're going to need to adjust these styles. // - // Note that because we're not specifing WS_CHILD, this window + // 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, whild owned windows are still - // relative to the desktop. (there are other subtlties as well + // 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. diff --git a/src/winconpty/winconpty.cpp b/src/winconpty/winconpty.cpp index e5331c73918..88f1549e00b 100644 --- a/src/winconpty/winconpty.cpp +++ b/src/winconpty/winconpty.cpp @@ -265,6 +265,8 @@ HRESULT _ClearPseudoConsole(_In_ const PseudoConsole* const pPty) // 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) @@ -278,7 +280,7 @@ HRESULT _ReparentPseudoConsole(_In_ const PseudoConsole* const pPty, _In_ const { const unsigned short id; const uint64_t hwnd; - } data{ PTY_SIGNAL_REPARENT_WINDOW, reinterpret_cast(newParent) }; + } data{ PTY_SIGNAL_REPARENT_WINDOW, (uint64_t)(newParent) }; #pragma pack(pop) const BOOL fSuccess = WriteFile(pPty->hSignal, &data, sizeof(data), nullptr, nullptr); From 5e54423864d4beaa68dac50f6cdf36d2240a24cc Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 12 Apr 2022 06:17:06 -0500 Subject: [PATCH 14/15] guess what, this wasn't needed, hooplah --- src/host/PtySignalInputThread.cpp | 24 ++++++------------------ src/host/PtySignalInputThread.hpp | 1 - src/host/VtIo.cpp | 3 +-- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index 5e40983a71d..cf564d0c9fb 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -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: // - // Return Value: @@ -67,6 +71,8 @@ void PtySignalInputThread::ConnectConsole() noexcept { _DoResizeWindow(*_earlyResize); } + + // If we were given a owner HWND, then manually start the pseudo window now. if (_earlyReparent) { _DoSetWindowParent(*_earlyReparent); @@ -187,24 +193,6 @@ void PtySignalInputThread::_DoSetWindowParent(const SetParentData& data) _pConApi->ReparentWindow(data.handle); } -// Method Description: -// - If we were given a owner HWND, then manually start the pseudo window now. -// 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: -// - -// Return Value: -// - -void PtySignalInputThread::StartPseudoWindowIfNeeded() -{ - if (_earlyReparent.has_value()) - { - ServiceLocator::LocatePseudoWindow(reinterpret_cast(_earlyReparent.value().handle)); - } -} - // Method Description: // - Retrieves bytes from the file stream and exits or throws errors should the pipe state // be compromised. diff --git a/src/host/PtySignalInputThread.hpp b/src/host/PtySignalInputThread.hpp index 499c158aa06..71d1ed27c83 100644 --- a/src/host/PtySignalInputThread.hpp +++ b/src/host/PtySignalInputThread.hpp @@ -36,7 +36,6 @@ namespace Microsoft::Console PtySignalInputThread& operator=(const PtySignalInputThread&) = delete; void ConnectConsole() noexcept; - void StartPseudoWindowIfNeeded(); private: enum class PtySignal : unsigned short diff --git a/src/host/VtIo.cpp b/src/host/VtIo.cpp index 040c655141d..3c44c132643 100644 --- a/src/host/VtIo.cpp +++ b/src/host/VtIo.cpp @@ -300,8 +300,7 @@ bool VtIo::IsUsingVt() const // 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. - _pPtySignalInputThread->StartPseudoWindowIfNeeded(); - + // // Let the signal thread know that the console is connected _pPtySignalInputThread->ConnectConsole(); } From a536bb8f27313f4ec655d06ce45b178a4ffe7759 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 12 Apr 2022 17:43:04 -0500 Subject: [PATCH 15/15] Update src/cascadia/TerminalApp/AppLogic.cpp --- src/cascadia/TerminalApp/AppLogic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index af1bb4c3ce2..fe6636a4f93 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -1641,5 +1641,4 @@ namespace winrt::TerminalApp::implementation { return _settings.GlobalSettings().ShowTitleInTitlebar(); } - }