385 lines
11 KiB
C++
385 lines
11 KiB
C++
// 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<IConsoleControl>& control)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<IConsoleControl> newControl;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
newControl = std::make_unique<Microsoft::Console::Interactivity::Win32::ConsoleControl>();
|
|
break;
|
|
|
|
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
case ApiLevel::OneCore:
|
|
newControl = std::make_unique<Microsoft::Console::Interactivity::OneCore::ConsoleControl>();
|
|
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<IConsoleInputThread>& thread)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<IConsoleInputThread> newThread;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
newThread = std::make_unique<Microsoft::Console::Interactivity::Win32::ConsoleInputThread>();
|
|
break;
|
|
|
|
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
case ApiLevel::OneCore:
|
|
newThread = std::make_unique<Microsoft::Console::Interactivity::OneCore::ConsoleInputThread>();
|
|
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<IHighDpiApi>& api)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<IHighDpiApi> newApi;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
newApi = std::make_unique<Microsoft::Console::Interactivity::Win32::WindowDpiApi>();
|
|
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<IWindowMetrics>& metrics)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<IWindowMetrics> newMetrics;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
newMetrics = std::make_unique<Microsoft::Console::Interactivity::Win32::WindowMetrics>();
|
|
break;
|
|
|
|
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
case ApiLevel::OneCore:
|
|
newMetrics = std::make_unique<Microsoft::Console::Interactivity::OneCore::WindowMetrics>();
|
|
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<IAccessibilityNotifier>& notifier)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<IAccessibilityNotifier> newNotifier;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
newNotifier = std::make_unique<Microsoft::Console::Interactivity::Win32::AccessibilityNotifier>();
|
|
break;
|
|
|
|
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
case ApiLevel::OneCore:
|
|
newNotifier = std::make_unique<Microsoft::Console::Interactivity::OneCore::AccessibilityNotifier>();
|
|
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<ISystemConfigurationProvider>& provider)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<ISystemConfigurationProvider> NewProvider;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
NewProvider = std::make_unique<Microsoft::Console::Interactivity::Win32::SystemConfigurationProvider>();
|
|
break;
|
|
|
|
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
case ApiLevel::OneCore:
|
|
NewProvider = std::make_unique<Microsoft::Console::Interactivity::OneCore::SystemConfigurationProvider>();
|
|
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<IInputServices>& services)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ApiLevel level;
|
|
status = ApiDetector::DetectNtUserWindow(&level);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
std::unique_ptr<IInputServices> newServices;
|
|
try
|
|
{
|
|
switch (level)
|
|
{
|
|
case ApiLevel::Win32:
|
|
newServices = std::make_unique<Microsoft::Console::Interactivity::Win32::InputServices>();
|
|
break;
|
|
|
|
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
case ApiLevel::OneCore:
|
|
newServices = std::make_unique<Microsoft::Console::Interactivity::OneCore::ConIoSrvComm>();
|
|
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
|