diff --git a/GlosSIConfig/qml/ShortcutProps.qml b/GlosSIConfig/qml/ShortcutProps.qml index 8d2a7da..cf43a91 100644 --- a/GlosSIConfig/qml/ShortcutProps.qml +++ b/GlosSIConfig/qml/ShortcutProps.qml @@ -752,7 +752,7 @@ Item { } } Button { - text: qsTr("Done") + text: qsTr("Save") highlighted: true enabled: nameInput.acceptableInput onClicked: function() { diff --git a/GlosSITarget/AppLauncher.cpp b/GlosSITarget/AppLauncher.cpp index e660331..2d2da76 100644 --- a/GlosSITarget/AppLauncher.cpp +++ b/GlosSITarget/AppLauncher.cpp @@ -167,6 +167,7 @@ void AppLauncher::getProcessHwnds() #ifdef _WIN32 void AppLauncher::UnPatchValveHooks() { + // TODO: move and re-use reusable unhook util from HidHide.cpp spdlog::debug("Unpatching Valve CreateProcess hook..."); // need to load addresses that way.. Otherwise we may land before some jumps... auto kernel32dll = GetModuleHandle(L"kernel32.dll"); @@ -176,12 +177,18 @@ void AppLauncher::UnPatchValveHooks() DWORD dw_old_protect, dw_bkup; const auto len = CREATE_PROC_ORIG_BYTES.size(); VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &dw_old_protect); //Change permissions of memory.. - for (DWORD i = 0; i < len; i++) //unpatch Valve's hook - { - *(address + i) = CREATE_PROC_ORIG_BYTES[i]; + const auto opcode = *(address); + if (opcode != 0xE9 && opcode != 0xE8 && opcode != 0xEB && opcode != 0xEA && opcode != 0xFF) { + spdlog::debug("\"CreateProcessW\" Doesn't appear to be hooked, skipping!"); + VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... + } else { + for (DWORD i = 0; i < len; i++) // unpatch Valve's hook + { + *(address + i) = CREATE_PROC_ORIG_BYTES[i]; + } + VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... + spdlog::trace("Unpatched CreateProcessW"); } - VirtualProtect(address, len, dw_old_protect, &dw_bkup); //Revert permission change... - spdlog::trace("Unpatched CreateProcessW"); } else { spdlog::error("failed to unpatch CreateProcessW"); diff --git a/GlosSITarget/HidHide.cpp b/GlosSITarget/HidHide.cpp index 1655e32..ef31fac 100644 --- a/GlosSITarget/HidHide.cpp +++ b/GlosSITarget/HidHide.cpp @@ -68,6 +68,10 @@ void HidHide::closeCtrlDevice() void HidHide::hideDevices(const std::filesystem::path& steam_path) { + if (!Settings::devices.hideDevices) { + spdlog::info("Hiding devices is disabled; Not un-patching valve hooks, not looking for HidHide"); + return; + } UnPatchValveHooks(); openCtrlDevice(); @@ -169,7 +173,7 @@ void HidHide::UnPatchValveHooks() for (const auto& name : ORIGINAL_BYTES | std::views::keys) { if (name.starts_with("Hid")) { UnPatchHook(name, hiddll); - } + } } } } @@ -182,12 +186,22 @@ void HidHide::UnPatchHook(const std::string& name, HMODULE module) if (!address) { spdlog::error("failed to unpatch \"{}\"", name); } - - auto bytes = ORIGINAL_BYTES.at(name); + std::string bytes; + if (Settings::isWin10 && ORIGINAL_BYTES_WIN10.contains(name)) { + bytes = ORIGINAL_BYTES_WIN10.at(name); + } else { + bytes = ORIGINAL_BYTES.at(name); + } DWORD dw_old_protect, dw_bkup; const auto len = bytes.size(); VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &dw_old_protect); // Change permissions of memory.. - for (DWORD i = 0; i < len; i++) //unpatch Valve's hook + const auto opcode = *(address); + if (!std::ranges::any_of(JUMP_INSTR_OPCODES, [&opcode](const auto& op) { return op == opcode; })) { + spdlog::debug("\"{}\" Doesn't appear to be hooked, skipping!", name); + VirtualProtect(address, len, dw_old_protect, &dw_bkup); // Revert permission change... + return; + } + for (DWORD i = 0; i < len; i++) // unpatch Valve's hook { *(address + i) = bytes[i]; } @@ -496,6 +510,12 @@ HidHide::SmallHidInfo HidHide::GetDeviceInfo(const DeviceInstancePath& instance_ res.name = (HidD_GetProductString(device_object.get(), buffer.data(), static_cast(sizeof(WCHAR) * buffer.size())) ? buffer : L""); + for (size_t i = 0; i < res.name.size(); ++i) { + if (res.name[i] == L'\0') { + res.name.resize(i + 1); + break; + } + } // Valve emulated gamepad PID/VID; mirrord by ViGEm if (attributes.VendorID == 0x28de /* && attributes.ProductID == 0x11FF*/) { res.name = std::wstring(L"ViGEm Emulated: ") + res.name; diff --git a/GlosSITarget/HidHide.h b/GlosSITarget/HidHide.h index 0f9c020..0f398bd 100644 --- a/GlosSITarget/HidHide.h +++ b/GlosSITarget/HidHide.h @@ -85,6 +85,19 @@ class HidHide { {"HidP_GetButtonCaps", "\x48\x83\xEC\x48\x49"}, }; + static inline const std::map ORIGINAL_BYTES_WIN10 = { + {"SetupDiEnumDeviceInfo", "\x40\x53\x56\x57\x41\x54\x41\x55"}, + {"SetupDiGetClassDevsW", "\x48\x8B\xC4\x48\x89\x58\x08"}, + }; + + static inline const std::vector JUMP_INSTR_OPCODES = { + 0xE9, + 0xE8, + 0xEB, + 0xEA, + 0xFF + }; + static void UnPatchValveHooks(); static void UnPatchHook(const std::string& name, HMODULE module); diff --git a/GlosSITarget/Overlay.cpp b/GlosSITarget/Overlay.cpp index a952dcb..23ff7b6 100644 --- a/GlosSITarget/Overlay.cpp +++ b/GlosSITarget/Overlay.cpp @@ -250,7 +250,7 @@ void Overlay::showLogs(ImGuiID dockspace_id) return res; }); } - if (logs.empty() || ( !enabled_ && !logs_contain_warn_or_worse && time_since_start_clock_.getElapsedTime().asSeconds() > HIDE_NORMAL_LOGS_AFTER_S)) + if (logs.empty() || ( !enabled_ && !force_enable_ && !logs_contain_warn_or_worse && time_since_start_clock_.getElapsedTime().asSeconds() > HIDE_NORMAL_LOGS_AFTER_S)) return; ImGui::SetNextWindowSizeConstraints({150, 150}, {1000, window_.getSize().y - 250.f}); if (!enabled_) { diff --git a/GlosSITarget/Settings.h b/GlosSITarget/Settings.h index 9e25bc9..bac7034 100644 --- a/GlosSITarget/Settings.h +++ b/GlosSITarget/Settings.h @@ -23,6 +23,12 @@ limitations under the License. #include #include +#ifdef WIN32 +#define NOMINMAX +#include +#endif + + namespace Settings { inline struct Launch { @@ -56,6 +62,7 @@ inline bool extendedLogging = false; inline std::filesystem::path settings_path_ = ""; + inline bool checkIsUwp(const std::wstring& launch_path) { if (launch_path.find(L"://") != std::wstring::npos) { @@ -68,6 +75,45 @@ inline bool checkIsUwp(const std::wstring& launch_path) return false; } +#ifdef WIN32 +inline bool isWin10 = false; + + typedef LONG NTSTATUS, *PNTSTATUS; +#define STATUS_SUCCESS (0x00000000) + +typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + +inline RTL_OSVERSIONINFOW GetRealOSVersion() +{ + HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); + if (hMod) { + RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (fxPtr != nullptr) { + RTL_OSVERSIONINFOW rovi = {0}; + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (STATUS_SUCCESS == fxPtr(&rovi)) { + return rovi; + } + } + } + RTL_OSVERSIONINFOW rovi = {0}; + return rovi; +} + +inline void checkWinVer() +{ + auto VN = GetRealOSVersion(); + isWin10 = VN.dwBuildNumber < 22000; + + if (isWin10) { + spdlog::info("Running on Windows 10"); + } else { + spdlog::info("Running on Windows 11"); + } + +} +#endif + inline void Parse(std::wstring arg1) { if (!arg1.ends_with(L".json")) { @@ -156,8 +202,7 @@ inline void Parse(std::wstring arg1) json_file.close(); - // c++ is stupid... - spdlog::debug(L"Read config file \"{}\"; config: {}", path.wstring(), std::filesystem::path(json.dump()).wstring()); + spdlog::debug("Read config file \"{}\"; config: {}", path.string(), json.dump()); if (launch.launch) { launch.isUWP = checkIsUwp(launch.launchPath); diff --git a/GlosSITarget/main.cpp b/GlosSITarget/main.cpp index ec6ee4e..238c5d7 100644 --- a/GlosSITarget/main.cpp +++ b/GlosSITarget/main.cpp @@ -158,6 +158,7 @@ int main(int argc, char* argv[]) argsv += i == 1 ? args[i] : std::wstring(L" ") + args[i]; } Settings::Parse(argsv); + Settings::checkWinVer(); SteamTarget target; #else // Code below is broken now due to parse requiring std::wstring instead of std:string. Sorry. std::string argsv = ""; diff --git a/UWPOverlayEnablerDLL/dllmain.cpp b/UWPOverlayEnablerDLL/dllmain.cpp index 2e2f1a3..e657f0d 100644 --- a/UWPOverlayEnablerDLL/dllmain.cpp +++ b/UWPOverlayEnablerDLL/dllmain.cpp @@ -55,6 +55,7 @@ There are two (known to me, at time of writing) ways to get a working overlay fo #include #include +#include enum ZBID { @@ -89,6 +90,10 @@ std::atomic allow_exit = false; std::atomic to_set_window_band = ZBID_SYSTEM_TOOLS; +std::chrono::time_point start_time; + +static constexpr int hook_timeout_seconds_ = 60; + BOOL WINAPI SetGlosSIWindowBand(HWND hWnd, HWND hwndInsertAfter, DWORD dwBand) { subhook::ScopedHookRemove remove(&SetWindowBandHook); @@ -103,6 +108,13 @@ BOOL WINAPI SetGlosSIWindowBand(HWND hWnd, HWND hwndInsertAfter, DWORD dwBand) auto success = SetWindowBand(glossi_hwnd, nullptr, to_set_window_band); allow_exit = true; spdlog::info("Set GlosSI Window Band to {}; success: {}", static_cast(to_set_window_band), success); + } else if (allow_exit == false) { + const auto time = std::chrono::system_clock::now(); + if (std::chrono::duration_cast(time - start_time).count() > hook_timeout_seconds_) + { + spdlog::info("GlosSI Window not found after {} seconds, exiting", hook_timeout_seconds_); + allow_exit = true; + } } return SetWindowBand(hWnd, hwndInsertAfter, dwBand); } @@ -208,6 +220,7 @@ BOOL APIENTRY DllMain( HMODULE hModule, const auto hpath = LoadLibrary(L"user32.dll"); if (hpath) { + start_time = std::chrono::system_clock::now(); spdlog::debug("Loaded user32.dll"); spdlog::debug("Installing SetWindowBand hook"); SetWindowBand = reinterpret_cast(GetProcAddress(hpath, "SetWindowBand")); diff --git a/deps/ViGEmClient b/deps/ViGEmClient index c8c312e..3bc2cee 160000 --- a/deps/ViGEmClient +++ b/deps/ViGEmClient @@ -1 +1 @@ -Subproject commit c8c312ef33d6112dbb8b86d5cd80d25716d32ff1 +Subproject commit 3bc2cee48ab0b10b5dd31323a621677175cfb00d diff --git a/download_release_deps.ps1 b/download_release_deps.ps1 index 9afd46b..04c2692 100644 --- a/download_release_deps.ps1 +++ b/download_release_deps.ps1 @@ -1,3 +1,3 @@ -Invoke-WebRequest -o ViGEmBusSetup_x64.exe https://github.com/ViGEm/ViGEmBus/releases/download/v1.18.367.0/ViGEmBus_1.18.367_x64_x86.exe +Invoke-WebRequest -o ViGEmBusSetup_x64.exe https://github.com/ViGEm/ViGEmBus/releases/download/v1.21.442.0/ViGEmBus_1.21.442_x64_x86_arm64.exe Invoke-WebRequest -o HidHideSetup.exe https://github.com/ViGEm/HidHide/releases/download/v1.2.98.0/HidHide_1.2.98_x64.exe Invoke-WebRequest -o vc_redist.x64.exe https://aka.ms/vs/16/release/vc_redist.x64.exe \ No newline at end of file