sdvx: prevent the game from trying a random ASIO driver (#488)

## Link to GitHub Issue, if one exists
n/a

## Description of change
SDVX EG final started to pick an ASIO driver at random and tries to open
it, which causes crashes / hangs if the driver is not compatible
(ASIO4ALL in particular)

Only allow the game to access `HKLM\SOFTWARE\ASIO` if the user has a
Xonar AE, or if ASIO was configured using -sdvxasio.

## Testing
Tested year 1 data and EG final.
This commit is contained in:
bicarus
2025-12-30 17:58:28 -08:00
committed by GitHub
parent b8e99e75e5
commit 8de7e5a9e4
2 changed files with 48 additions and 8 deletions
+47 -8
View File
@@ -48,7 +48,7 @@ namespace games::sdvx {
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM; SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
bool ENABLE_COM_PORT_SCAN_HOOK = false; bool ENABLE_COM_PORT_SCAN_HOOK = false;
std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt; bool USE_ASIO = false;
std::optional<std::string> ASIO_DRIVER = std::nullopt; std::optional<std::string> ASIO_DRIVER = std::nullopt;
// states // states
@@ -57,13 +57,22 @@ namespace games::sdvx {
static HKEY real_asio_device_reg_handle = nullptr; static HKEY real_asio_device_reg_handle = nullptr;
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) { static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
if (lpSubKey != nullptr && phkResult != nullptr) { if (lpSubKey != nullptr &&
if (hKey == HKEY_LOCAL_MACHINE && phkResult != nullptr &&
ASIO_DRIVER.has_value() && hKey == HKEY_LOCAL_MACHINE &&
_stricmp(lpSubKey, "software\\asio") == 0) _stricmp(lpSubKey, "software\\asio") == 0) {
{
*phkResult = PARENT_ASIO_REG_HANDLE;
// prevent the game from randomly picking an ASIO device
if (!USE_ASIO) {
log_info(
"sdvx::asio",
"game tried to access HKLM\\SOFTWARE\\ASIO but ASIO is disabled; "
"access prevented, ASIO init will fail");
return ERROR_FILE_NOT_FOUND;
}
// convince the game to use our hook (so we can swap in the preferred device)
if (ASIO_DRIVER.has_value()) {
*phkResult = PARENT_ASIO_REG_HANDLE;
return RegOpenKeyA_orig(hKey, lpSubKey, &real_asio_reg_handle); return RegOpenKeyA_orig(hKey, lpSubKey, &real_asio_reg_handle);
} }
} }
@@ -110,7 +119,7 @@ namespace games::sdvx {
lpSubKey != nullptr && phkResult != nullptr && lpSubKey != nullptr && phkResult != nullptr &&
_stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) { _stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) {
log_info("sdvx::io", "hook access to HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA"); log_info("sdvx::io", "hook access to HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
return 2; // ERROR_FILE_NOT_FOUND return ERROR_FILE_NOT_FOUND;
} }
return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult); return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult);
@@ -230,6 +239,32 @@ namespace games::sdvx {
return false; return false;
} }
void SDVXGame::detect_sound_output_device() {
USE_ASIO = false;
// if the user specified a value for -sdvxasio, use asio
if (ASIO_DRIVER.has_value()) {
log_misc(
"sdvx",
"-sdvxasio is set to \"{}\"", ASIO_DRIVER.value());
USE_ASIO = true;
} else {
// see if XONAR AE is present; if so, use that
HKEY subkey;
LSTATUS result;
result = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\ASIO\\XONAR SOUND CARD(64)", &subkey);
if (result == ERROR_SUCCESS) {
RegCloseKey(subkey);
USE_ASIO = true;
log_misc(
"sdvx",
"found HKLM\\SOFTWARE\\ASIO\\XONAR SOUND CARD(64)");
}
}
if (!USE_ASIO) {
log_misc("sdvx", "asio not configured");
}
}
typedef void **(__fastcall *volume_set_t)(uint64_t, uint64_t, uint64_t); typedef void **(__fastcall *volume_set_t)(uint64_t, uint64_t, uint64_t);
static volume_set_t volume_set_orig = nullptr; static volume_set_t volume_set_orig = nullptr;
static void **__fastcall volume_set_hook(uint64_t vol_sound, uint64_t vol_woofer, uint64_t vol_headphone) { static void **__fastcall volume_set_hook(uint64_t vol_sound, uint64_t vol_woofer, uint64_t vol_headphone) {
@@ -323,6 +358,10 @@ namespace games::sdvx {
} }
#endif #endif
#ifdef SPICE64
this->detect_sound_output_device();
#endif
} }
void SDVXGame::attach() { void SDVXGame::attach() {
+1
View File
@@ -39,5 +39,6 @@ namespace games::sdvx {
// not depend on the fact that SDVX module is active (since it can be // not depend on the fact that SDVX module is active (since it can be
// inactive on cabs or partial I/O setup) // inactive on cabs or partial I/O setup)
bool VALKYRIE_MODEL = false; bool VALKYRIE_MODEL = false;
void detect_sound_output_device();
}; };
} }