// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "precomp.h" #include "InteractivityFactory.hpp" #ifdef BUILD_ONECORE_INTERACTIVITY #include "..\onecore\AccessibilityNotifier.hpp" #include "..\onecore\ConsoleControl.hpp" #include "..\onecore\ConsoleInputThread.hpp" #include "..\onecore\ConsoleWindow.hpp" #include "..\onecore\ConIoSrvComm.hpp" #include "..\onecore\SystemConfigurationProvider.hpp" #include "..\onecore\WindowMetrics.hpp" #endif #include "../win32/AccessibilityNotifier.hpp" #include "../win32/ConsoleControl.hpp" #include "../win32/ConsoleInputThread.hpp" #include "../win32/InputServices.hpp" #include "../win32/WindowDpiApi.hpp" #include "../win32/WindowMetrics.hpp" #include "../win32/SystemConfigurationProvider.hpp" #pragma hdrstop using namespace std; using namespace Microsoft::Console::Interactivity; #pragma region Public Methods [[nodiscard]] NTSTATUS InteractivityFactory::CreateConsoleControl(_Inout_ std::unique_ptr& control) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr newControl; try { switch (level) { case ApiLevel::Win32: newControl = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: newControl = std::make_unique(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { control.swap(newControl); } } return status; } [[nodiscard]] NTSTATUS InteractivityFactory::CreateConsoleInputThread(_Inout_ std::unique_ptr& thread) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr newThread; try { switch (level) { case ApiLevel::Win32: newThread = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: newThread = std::make_unique(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { thread.swap(newThread); } } return status; } [[nodiscard]] NTSTATUS InteractivityFactory::CreateHighDpiApi(_Inout_ std::unique_ptr& api) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr newApi; try { switch (level) { case ApiLevel::Win32: newApi = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: newApi.reset(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { api.swap(newApi); } } return status; } [[nodiscard]] NTSTATUS InteractivityFactory::CreateWindowMetrics(_Inout_ std::unique_ptr& metrics) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr newMetrics; try { switch (level) { case ApiLevel::Win32: newMetrics = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: newMetrics = std::make_unique(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { metrics.swap(newMetrics); } } return status; } [[nodiscard]] NTSTATUS InteractivityFactory::CreateAccessibilityNotifier(_Inout_ std::unique_ptr& notifier) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr newNotifier; try { switch (level) { case ApiLevel::Win32: newNotifier = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: newNotifier = std::make_unique(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { notifier.swap(newNotifier); } } return status; } [[nodiscard]] NTSTATUS InteractivityFactory::CreateSystemConfigurationProvider(_Inout_ std::unique_ptr& provider) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr NewProvider; try { switch (level) { case ApiLevel::Win32: NewProvider = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: NewProvider = std::make_unique(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { provider.swap(NewProvider); } } return status; } [[nodiscard]] NTSTATUS InteractivityFactory::CreateInputServices(_Inout_ std::unique_ptr& services) { NTSTATUS status = STATUS_SUCCESS; ApiLevel level; status = ApiDetector::DetectNtUserWindow(&level); if (NT_SUCCESS(status)) { std::unique_ptr newServices; try { switch (level) { case ApiLevel::Win32: newServices = std::make_unique(); break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: newServices = std::make_unique(); break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } if (NT_SUCCESS(status)) { services.swap(newServices); } } return status; } // Method Description: // - Attempts to instantiate a "pseudo window" for when we're operating in // pseudoconsole mode. There are some tools (cygwin & derivatives) that use // the GetConsoleWindow API to uniquely identify console sessions. This // function is used to create an invisible window for that scenario, so // that GetConsoleWindow returns a real value. // Arguments: // - 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) { hwnd = nullptr; ApiLevel level; NTSTATUS status = ApiDetector::DetectNtUserWindow(&level); ; if (NT_SUCCESS(status)) { try { static const wchar_t* const PSEUDO_WINDOW_CLASS = L"PseudoConsoleWindow"; WNDCLASS pseudoClass{ 0 }; switch (level) { case ApiLevel::Win32: pseudoClass.lpszClassName = PSEUDO_WINDOW_CLASS; pseudoClass.lpfnWndProc = DefWindowProc; RegisterClass(&pseudoClass); // Attempt to create window hwnd = CreateWindowExW( 0, PSEUDO_WINDOW_CLASS, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, HWND_DESKTOP, nullptr, nullptr, nullptr); if (hwnd == nullptr) { DWORD const gle = GetLastError(); status = NTSTATUS_FROM_WIN32(gle); } break; #ifdef BUILD_ONECORE_INTERACTIVITY case ApiLevel::OneCore: hwnd = 0; status = STATUS_SUCCESS; break; #endif default: status = STATUS_INVALID_LEVEL; break; } } catch (...) { status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException()); } } return status; } #pragma endregion