Files
spice2x_spice2x.github.io/src/spice2x/hooks/libraryhook.cpp
T
Jiongjia LuandCodex 2b6e76730b Dance around early support (#897)
## Link to GitHub Issue or related Pull Request, if one exists
N/A

## Description of change
This PR add initial supports for running Dance aRound in window mode,
with keyboard, cardio supports.

## Testing
- Tested game play under Windows 10 using Kinect V1 with my visionpose
compatible layer (https://github.com/Avimitin/dance-around-anygear)


https://github.com/user-attachments/assets/4b821dcf-751d-4953-b626-4a9491569183

- Tested full game play, user profile saving with Asphyxia

Assisted by AI.

---------

Co-authored-by: Codex <codex@openai.com>
2026-09-12 09:51:23 -07:00

154 lines
4.5 KiB
C++

#include "libraryhook.h"
#include <mutex>
#include <shared_mutex>
#include "external/robin_hood.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/utils.h"
static bool LHOOK_ENABLED = false;
// SDK plugins can add aliases while other threads load DLLs.
static std::shared_mutex LIBRARIES_MUTEX;
static robin_hood::unordered_map<std::string, HMODULE> LIBRARIES_A;
static robin_hood::unordered_map<std::wstring, HMODULE> LIBRARIES_W;
static robin_hood::unordered_map<std::string, FARPROC> PROCS;
static decltype(LoadLibraryA) *LoadLibraryA_orig = nullptr;
static decltype(LoadLibraryW) *LoadLibraryW_orig = nullptr;
static decltype(LoadLibraryExW) *LoadLibraryExW_orig = nullptr;
static decltype(GetModuleHandleA) *GetModuleHandleA_orig = nullptr;
static decltype(GetModuleHandleW) *GetModuleHandleW_orig = nullptr;
static decltype(GetProcAddress) *GetProcAddress_orig = nullptr;
static HMODULE WINAPI LoadLibraryA_hook(LPCTSTR lpFileName) {
// check hooks
if (lpFileName) {
std::shared_lock lock(LIBRARIES_MUTEX);
auto module = LIBRARIES_A.find(lpFileName);
if (module != LIBRARIES_A.end()) {
return module->second;
}
}
// fallback
return LoadLibraryA_orig(lpFileName);
}
static HMODULE WINAPI LoadLibraryW_hook(LPCWSTR lpFileName) {
// check hooks
if (lpFileName) {
std::shared_lock lock(LIBRARIES_MUTEX);
auto module = LIBRARIES_W.find(lpFileName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return LoadLibraryW_orig(lpFileName);
}
static HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags) {
// check hooks
if (lpFileName) {
std::shared_lock lock(LIBRARIES_MUTEX);
auto module = LIBRARIES_W.find(lpFileName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return LoadLibraryExW_orig(lpFileName, hFile, dwFlags);
}
static HMODULE WINAPI GetModuleHandleA_hook(LPCSTR lpModuleName) {
// check hooks
if (lpModuleName) {
std::shared_lock lock(LIBRARIES_MUTEX);
auto module = LIBRARIES_A.find(lpModuleName);
if (module != LIBRARIES_A.end()) {
return module->second;
}
}
// fallback
return GetModuleHandleA_orig(lpModuleName);
}
static HMODULE WINAPI GetModuleHandleW_hook(LPCWSTR lpModuleName) {
// check hooks
if (lpModuleName) {
std::shared_lock lock(LIBRARIES_MUTEX);
auto module = LIBRARIES_W.find(lpModuleName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return GetModuleHandleW_orig(lpModuleName);
}
static FARPROC WINAPI GetProcAddress_hook(HMODULE hModule, LPCSTR lpProcName) {
// check for ordinal
if (reinterpret_cast<uintptr_t>(lpProcName) <= UINT16_MAX) {
// fallback
return GetProcAddress_orig(hModule, lpProcName);
}
// check hooks
if (lpProcName) {
auto proc = PROCS.find(lpProcName);
if (proc != PROCS.end()) {
return proc->second;
}
}
// fallback
return GetProcAddress_orig(hModule, lpProcName);
}
void libraryhook_enable(HMODULE module) {
log_info("libraryhook", "LibraryHook Attach");
if (LHOOK_ENABLED) {
return;
}
// detour
detour::trampoline_try("kernel32.dll", "LoadLibraryA", LoadLibraryA_hook, &LoadLibraryA_orig);
detour::trampoline_try("kernel32.dll", "LoadLibraryW", LoadLibraryW_hook, &LoadLibraryW_orig);
detour::trampoline_try("kernel32.dll", "LoadLibraryExW", LoadLibraryExW_hook, &LoadLibraryExW_orig);
detour::trampoline_try("kernel32.dll", "GetModuleHandleA", GetModuleHandleA_hook, &GetModuleHandleA_orig);
detour::trampoline_try("kernel32.dll", "GetModuleHandleW", GetModuleHandleW_hook, &GetModuleHandleW_orig);
detour::trampoline_try("kernel32.dll", "GetProcAddress", GetProcAddress_hook, &GetProcAddress_orig);
// set enabled
LHOOK_ENABLED = true;
}
void libraryhook_hook_library(std::string library_name, HMODULE library_address) {
const auto library_name_w = s2ws(library_name);
std::unique_lock lock(LIBRARIES_MUTEX);
// add library to list
LIBRARIES_W.insert_or_assign(library_name_w, library_address);
LIBRARIES_A.insert_or_assign(std::move(library_name), library_address);
}
void libraryhook_hook_proc(std::string proc_name, FARPROC proc_address) {
// add proc to list
PROCS.insert_or_assign(std::move(proc_name), proc_address);
}