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;
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;
// states
@@ -57,13 +57,22 @@ namespace games::sdvx {
static HKEY real_asio_device_reg_handle = nullptr;
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
if (lpSubKey != nullptr && phkResult != nullptr) {
if (hKey == HKEY_LOCAL_MACHINE &&
ASIO_DRIVER.has_value() &&
_stricmp(lpSubKey, "software\\asio") == 0)
{
*phkResult = PARENT_ASIO_REG_HANDLE;
if (lpSubKey != nullptr &&
phkResult != nullptr &&
hKey == HKEY_LOCAL_MACHINE &&
_stricmp(lpSubKey, "software\\asio") == 0) {
// 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);
}
}
@@ -110,7 +119,7 @@ namespace games::sdvx {
lpSubKey != nullptr && phkResult != nullptr &&
_stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) {
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);
@@ -230,6 +239,32 @@ namespace games::sdvx {
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);
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) {
@@ -323,6 +358,10 @@ namespace games::sdvx {
}
#endif
#ifdef SPICE64
this->detect_sound_output_device();
#endif
}
void SDVXGame::attach() {