mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-21 22:37:19 +00:00
Merge 'dev/migrie/f/z-order-owner' into 'dev/migrie/b/2988-niksa-msgs-prototype'
This commit is contained in:
1
.github/actions/spelling/allow/apis.txt
vendored
1
.github/actions/spelling/allow/apis.txt
vendored
@@ -144,6 +144,7 @@ REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
ROOTOWNER
|
||||
RSHIFT
|
||||
SACL
|
||||
schandle
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -46,6 +46,8 @@ namespace TerminalApp
|
||||
// registered?" when it definitely is.
|
||||
void Create();
|
||||
|
||||
void SetOwnerHwnd(UInt64 owner);
|
||||
|
||||
Boolean IsUwp();
|
||||
void RunAsUwp();
|
||||
Boolean IsElevated();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -24,5 +24,8 @@ namespace Microsoft.Terminal.Control
|
||||
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
||||
|
||||
Microsoft.Terminal.Core.Scheme ColorScheme { get; set; };
|
||||
|
||||
UInt64 OwningHwnd;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -41,6 +41,11 @@ IslandWindow::~IslandWindow()
|
||||
_source.Close();
|
||||
}
|
||||
|
||||
HWND IslandWindow::GetInteropHandle() const
|
||||
{
|
||||
return _interopWindowHandle;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create the actual window that we'll use for the application.
|
||||
// Arguments:
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
virtual void MakeWindow() noexcept;
|
||||
void Close();
|
||||
virtual void OnSize(const UINT width, const UINT height);
|
||||
HWND GetInteropHandle() const;
|
||||
|
||||
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
|
||||
void OnResize(const UINT width, const UINT height) override;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Microsoft::Console::Interactivity
|
||||
[[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider) = 0;
|
||||
|
||||
virtual void SetPseudoWindowCallback(std::function<void(bool)> func) = 0;
|
||||
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0;
|
||||
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd, const HWND owner) = 0;
|
||||
};
|
||||
|
||||
inline IInteractivityFactory::~IInteractivityFactory() {}
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Microsoft::Console::Interactivity
|
||||
static Globals& LocateGlobals();
|
||||
|
||||
static void SetPseudoWindowCallback(std::function<void(bool)> func);
|
||||
static HWND LocatePseudoWindow();
|
||||
static HWND LocatePseudoWindow(const HWND owner = 0 /*HWND_DESKTOP*/);
|
||||
|
||||
protected:
|
||||
ServiceLocator(ServiceLocator const&) = delete;
|
||||
|
||||
@@ -112,5 +112,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
virtual void UpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
|
||||
const SIZE cellSize,
|
||||
const size_t centeringHint) = 0;
|
||||
|
||||
virtual void ReparentWindow(const uint64_t handle) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -428,6 +428,11 @@ public:
|
||||
VERIFY_ARE_EQUAL(_expectedCellSize.cy, cellSize.cy);
|
||||
}
|
||||
|
||||
void ReparentWindow(const uint64_t /*handle*/)
|
||||
{
|
||||
Log::Comment(L"UpdateSoftFont MOCK called...");
|
||||
}
|
||||
|
||||
void PrepData()
|
||||
{
|
||||
PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter.
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user