From 5fda8ee8ec3315a209bd1608198aea4b4c977c40 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Thu, 7 Apr 2022 06:34:39 +0200 Subject: [PATCH] Core/WGInput: Dynamically load winrt function addresses. --- .../ControllerInterface/WGInput/WGInput.cpp | 125 ++++++++++++++++-- 1 file changed, 114 insertions(+), 11 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/WGInput/WGInput.cpp b/Source/Core/InputCommon/ControllerInterface/WGInput/WGInput.cpp index 1fac7866f4..46beb409cd 100644 --- a/Source/Core/InputCommon/ControllerInterface/WGInput/WGInput.cpp +++ b/Source/Core/InputCommon/ControllerInterface/WGInput/WGInput.cpp @@ -12,11 +12,17 @@ #include #include +#include "Common/DynamicLibrary.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" -#pragma comment(lib, "runtimeobject.lib") +using PIsApiSetImplemented = BOOL(APIENTRY*)(PCSTR Contract); +using PRoInitialize = decltype(&RoInitialize); +using PRoUninitialize = decltype(&RoUninitialize); +using PRoGetActivationFactory = decltype(&RoGetActivationFactory); +using PWindowsCreateStringReference = decltype(&WindowsCreateStringReference); +using PWindowsGetStringRawBuffer = decltype(&WindowsGetStringRawBuffer); namespace WGI = ABI::Windows::Gaming::Input; using ABI::Windows::Foundation::Collections::IVectorView; @@ -26,6 +32,11 @@ namespace { bool g_runtime_initialized = false; bool g_runtime_needs_deinit = false; +PRoInitialize g_RoInitialize_address = nullptr; +PRoUninitialize g_RoUninitialize_address = nullptr; +PRoGetActivationFactory g_RoGetActivationFactory_address = nullptr; +PWindowsCreateStringReference g_WindowsCreateStringReference_address = nullptr; +PWindowsGetStringRawBuffer g_WindowsGetStringRawBuffer_address = nullptr; } // namespace namespace ciface::WGInput @@ -571,12 +582,77 @@ private: ControlState m_battery_level = 0; }; +static bool LoadFunctionPointers() +{ + static Common::DynamicLibrary winrt_l1_1_0_handle; + static Common::DynamicLibrary winrt_string_l1_1_0_handle; + if (!winrt_l1_1_0_handle.IsOpen() && !winrt_string_l1_1_0_handle.IsOpen()) + { + Common::DynamicLibrary kernelBase("KernelBase.dll"); + if (!kernelBase.IsOpen()) + return false; + + void* const IsApiSetImplemented_address = kernelBase.GetSymbolAddress("IsApiSetImplemented"); + if (!IsApiSetImplemented_address) + return false; + if (!static_cast(IsApiSetImplemented_address)( + "api-ms-win-core-winrt-l1-1-0")) + { + return false; + } + if (!static_cast(IsApiSetImplemented_address)( + "api-ms-win-core-winrt-string-l1-1-0")) + { + return false; + } + + winrt_l1_1_0_handle.Open("api-ms-win-core-winrt-l1-1-0.dll"); + winrt_string_l1_1_0_handle.Open("api-ms-win-core-winrt-string-l1-1-0.dll"); + } + + if (!winrt_l1_1_0_handle.IsOpen() || !winrt_string_l1_1_0_handle.IsOpen()) + return false; + + g_RoInitialize_address = + static_cast(winrt_l1_1_0_handle.GetSymbolAddress("RoInitialize")); + if (!g_RoInitialize_address) + return false; + + g_RoUninitialize_address = + static_cast(winrt_l1_1_0_handle.GetSymbolAddress("RoUninitialize")); + if (!g_RoUninitialize_address) + return false; + + g_RoGetActivationFactory_address = static_cast( + winrt_l1_1_0_handle.GetSymbolAddress("RoGetActivationFactory")); + if (!g_RoGetActivationFactory_address) + return false; + + g_WindowsCreateStringReference_address = static_cast( + winrt_string_l1_1_0_handle.GetSymbolAddress("WindowsCreateStringReference")); + if (!g_WindowsCreateStringReference_address) + return false; + + g_WindowsGetStringRawBuffer_address = static_cast( + winrt_string_l1_1_0_handle.GetSymbolAddress("WindowsGetStringRawBuffer")); + if (!g_WindowsGetStringRawBuffer_address) + return false; + + return true; +} + void Init() { if (g_runtime_initialized) return; - const HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED); + if (!LoadFunctionPointers()) + { + ERROR_LOG(CONTROLLERINTERFACE, "WGInput: System lacks support, skipping init."); + return; + } + + const HRESULT hr = g_RoInitialize_address(RO_INIT_MULTITHREADED); switch (hr) { case S_OK: @@ -602,13 +678,21 @@ void DeInit() if (g_runtime_needs_deinit) { - RoUninitialize(); + g_RoUninitialize_address(); g_runtime_needs_deinit = false; } g_runtime_initialized = false; } +template +static HRESULT WindowsCreateStringReferenceAutoSizeWrapper(wchar_t const (&source_string)[size], + HSTRING_HEADER* hstring_header, + HSTRING* hstring) +{ + return g_WindowsCreateStringReference_address(source_string, size - 1, hstring_header, hstring); +} + void PopulateDevices() { if (!g_runtime_initialized) @@ -617,8 +701,6 @@ void PopulateDevices() g_controller_interface.RemoveDevice( [](const auto* dev) { return dev->GetSource() == SOURCE_NAME; }); - using Microsoft::WRL::Wrappers::HStringReference; - // WGI Interfaces to potentially use: // Gamepad: Buttons, 2x Sticks and 2x Triggers, 4x Vibration Motors // RawGameController: Buttons, Switches (Hats), Axes, Haptics @@ -628,18 +710,36 @@ void PopulateDevices() // RacingWheel: Buttons, Clutch, Handbrake, PatternShifterGear, Throttle, Wheel, WheelMotor // UINavigationController: Directions, Scrolling, etc. + HSTRING_HEADER header_raw_game_controller; + HSTRING hstr_raw_game_controller; + if (FAILED(WindowsCreateStringReferenceAutoSizeWrapper(L"Windows.Gaming.Input.RawGameController", + &header_raw_game_controller, + &hstr_raw_game_controller))) + { + ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to create string reference."); + return; + } + + HSTRING_HEADER header_gamepad; + HSTRING hstr_gamepad; + if (FAILED(WindowsCreateStringReferenceAutoSizeWrapper(L"Windows.Gaming.Input.Gamepad", + &header_gamepad, &hstr_gamepad))) + { + ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to create string reference."); + return; + } + ComPtr raw_stats; - if (FAILED( - RoGetActivationFactory(HStringReference(L"Windows.Gaming.Input.RawGameController").Get(), - __uuidof(WGI::IRawGameControllerStatics), &raw_stats))) + if (FAILED(g_RoGetActivationFactory_address( + hstr_raw_game_controller, __uuidof(WGI::IRawGameControllerStatics), &raw_stats))) { ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to get IRawGameControllerStatics."); return; } ComPtr gamepad_stats; - if (FAILED(RoGetActivationFactory(HStringReference(L"Windows.Gaming.Input.Gamepad").Get(), - __uuidof(WGI::IGamepadStatics2), &gamepad_stats))) + if (FAILED(g_RoGetActivationFactory_address(hstr_gamepad, __uuidof(WGI::IGamepadStatics2), + &gamepad_stats))) { ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to get IGamepadStatics2."); return; @@ -667,7 +767,10 @@ void PopulateDevices() { HSTRING hstr = {}; if (SUCCEEDED(rgc2->get_DisplayName(&hstr)) && hstr) - device_name = StripSpaces(WStringToUTF8(WindowsGetStringRawBuffer(hstr, nullptr))); + { + device_name = + StripSpaces(WStringToUTF8(g_WindowsGetStringRawBuffer_address(hstr, nullptr))); + } } if (device_name.empty())