Merge 'dev/migrie/f/z-order-owner' into 'dev/migrie/b/2988-niksa-msgs-prototype'

This commit is contained in:
Mike Griese
2022-03-29 06:56:41 -05:00
parent b777c51340
commit b742e93285
33 changed files with 424 additions and 11 deletions

View File

@@ -144,6 +144,7 @@ REGCLS
RETURNCMD
rfind
roundf
ROOTOWNER
RSHIFT
SACL
schandle

View File

@@ -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;

View File

@@ -46,6 +46,8 @@ namespace TerminalApp
// registered?" when it definitely is.
void Create();
void SetOwnerHwnd(UInt64 owner);
Boolean IsUwp();
void RunAsUwp();
Boolean IsElevated();

View File

@@ -2426,6 +2426,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<uint64_t>(_ownerHwnd));
return term;
}

View File

@@ -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);

View File

@@ -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<HWND>(_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<HWND>(_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<HWND>(newParent)));
}
}
void ConptyConnection::Close() noexcept
try
{

View File

@@ -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{};

View File

@@ -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();

View File

@@ -264,6 +264,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto height = vp.Height();
_connection.Resize(height, width);
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);

View File

@@ -170,6 +170,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void WindowVisibilityChanged(const bool showOrHide);
WINRT_PROPERTY(uint64_t, OwningHwnd, 0);
RUNTIME_SETTING(double, Opacity, _settings->Opacity());
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());

View File

@@ -24,5 +24,8 @@ namespace Microsoft.Terminal.Control
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
Microsoft.Terminal.Core.Scheme ColorScheme { get; set; };
UInt64 OwningHwnd;
};
}

View File

@@ -2790,4 +2790,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void TermControl::OwningHwnd(uint64_t owner)
{
_core.OwningHwnd(owner);
}
uint64_t TermControl::OwningHwnd()
{
return _core.OwningHwnd();
}
}

View File

@@ -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);

View File

@@ -335,6 +335,8 @@ void AppHost::Initialize()
if (auto withWindow{ _logic.try_as<IInitializeWithWindow>() })
{
withWindow->Initialize(_window->GetHandle());
// _logic.SetOwnerHwnd(reinterpret_cast<uint64_t>(_window->GetInteropHandle()));
_logic.SetOwnerHwnd(reinterpret_cast<uint64_t>(_window->GetHandle()));
}
if (_useNonClientArea)

View File

@@ -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:

View File

@@ -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;

View File

@@ -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.

View File

@@ -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();
@@ -62,5 +68,8 @@ namespace Microsoft::Console
bool _consoleConnected;
std::optional<ResizeWindowData> _earlyResize;
std::unique_ptr<Microsoft::Console::VirtualTerminal::ConGetSet> _pConApi;
public:
std::optional<SetParentData> _earlyReparent;
};
}

View File

@@ -258,6 +258,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<HWND>(_pPtySignalInputThread->_earlyReparent.value().handle));
}
// Let the signal thread know that the console is connected
_pPtySignalInputThread->ConnectConsole();
}

View File

@@ -905,3 +905,13 @@ 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 (const auto psuedoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast<HWND>(handle)) })
{
LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast<HWND>(handle)));
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -293,7 +293,7 @@ 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;
@@ -313,9 +313,25 @@ using namespace Microsoft::Console::Interactivity;
pseudoClass.lpfnWndProc = s_PseudoWindowProc;
RegisterClass(&pseudoClass);
// const auto windowStyle = (owner == HWND_DESKTOP) ? WS_OVERLAPPEDWINDOW : WS_CHILD;
const auto windowStyle = WS_OVERLAPPEDWINDOW;
// Attempt to create window
hwnd = CreateWindowExW(
WS_EX_TOOLWINDOW, PSEUDO_WINDOW_CLASS, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, HWND_DESKTOP, nullptr, nullptr, this);
WS_EX_TOOLWINDOW,
PSEUDO_WINDOW_CLASS,
nullptr,
windowStyle, //WS_CHILD, //WS_OVERLAPPEDWINDOW,
0,
0,
0,
0,
// Niksa just had the parent as HWND_DESKTOP always,
// This branch tests a merged version of the prototypes
owner /*(HWND)0x00070C6A*/ /*HWND_DESKTOP*/, // parent
nullptr,
nullptr,
this);
if (hwnd == nullptr)
{
DWORD const gle = GetLastError();

View File

@@ -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

View File

@@ -312,7 +312,7 @@ void ServiceLocator::SetPseudoWindowCallback(std::function<void(bool)> func)
// - <none>
// 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 +325,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);
}
@@ -335,7 +335,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 conveniently return 0 when we're on OneCore.
// if (const auto psuedoHwnd{ LocatePseudoWindow() })
// {
// ::SetParent(psuedoHwnd, newParent);
// }
// }
#pragma endregion

View File

@@ -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() {}

View File

@@ -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;

View File

@@ -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;
};
}

View File

@@ -428,6 +428,11 @@ public:
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.

View File

@@ -6,7 +6,7 @@
<RootNamespace>Scratch</RootNamespace>
<ProjectName>Scratch</ProjectName>
<TargetName>Scratch</TargetName>
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<Import Project="..\..\common.build.pre.props" />
<ItemGroup>
@@ -21,6 +21,14 @@
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<!-- subsume fmt, one of our dependencies, into contypes. -->
<ProjectReference Include="..\..\dep\fmt\fmt.vcxproj">
<Project>{6bae5851-50d5-4934-8d5e-30361a8a40f3}</Project>
</ProjectReference>
</ItemGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="..\..\common.build.post.props" />
<Import Project="..\..\common.build.tests.props" />

View File

@@ -1,10 +1,216 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "../../inc/LibraryIncludes.h"
#include <windows.h>
// This wmain exists for help in writing scratch programs while debugging.
int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/)
// 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<unsigned long long>(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<unsigned long long>(handle)).c_str());
wprintf(fmt::format(L"\t\towner: {}\n", reinterpret_cast<unsigned long long>(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<unsigned long long>(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<unsigned long long>(hwnd)).c_str());
// const auto newHwnd{ find_main_window(pid) };
// wprintf(fmt::format(L"newHwnd: {}\n", reinterpret_cast<unsigned long long>(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<unsigned long long>(consoleWindow)).c_str());
const auto mainHwnd{ find_main_window(pid) };
wprintf(fmt::format(L"mainHwnd: {0:#010x}\n", reinterpret_cast<unsigned long long>(mainHwnd)).c_str());
const auto consoleParent{ GetParent(consoleWindow) };
wprintf(fmt::format(L"parent: {0:#010x}\n", reinterpret_cast<unsigned long long>(consoleParent)).c_str());
const auto consoleOwner{ GetWindow(consoleWindow, GW_OWNER) };
wprintf(fmt::format(L"owner: {0:#010x}\n", reinterpret_cast<unsigned long long>(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<unsigned long long>(consoleAncestor_PARENT)).c_str());
wprintf(fmt::format(L"Ancestor_ROOT: {0:#010x}\n", reinterpret_cast<unsigned long long>(consoleAncestor_ROOT)).c_str());
wprintf(fmt::format(L"Ancestor_ROOTOWNER: {0:#010x}\n", reinterpret_cast<unsigned long long>(consoleAncestor_ROOTOWNER)).c_str());
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;
}

View File

@@ -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<uint64_t>(newParent);
} data{ PTY_SIGNAL_REPARENT_WINDOW, reinterpret_cast<uint64_t>(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

View File

@@ -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);