diff --git a/common/board/config.c b/common/board/config.c index 9f915cb..36b00ca 100644 --- a/common/board/config.c +++ b/common/board/config.c @@ -11,6 +11,7 @@ #include "board/vfd.h" #include "util/dprintf.h" +#include "util/io-path.h" // Check windows #if _WIN32 || _WIN64 @@ -44,24 +45,26 @@ static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *fil // Always empty, due to amdaemon being 64 bit in 32 bit mode memset(cfg->path, 0, sizeof(cfg->path)); #elif defined(ENV64BIT) - GetPrivateProfileStringW( - L"aimeio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"aimeio", + L"path", + L"SEGATOOLS_AIMEIO_PATH", + L"aimeio.dll", filename); #else #error "Unknown environment" #endif } else { - GetPrivateProfileStringW( - L"aimeio", - L"path", - L"", - cfg->path, - _countof(cfg->path), - filename); + io_path_config_load( + cfg->path, + _countof(cfg->path), + L"aimeio", + L"path", + L"SEGATOOLS_AIMEIO_PATH", + L"aimeio.dll", + filename); } } diff --git a/common/hooklib/config.c b/common/hooklib/config.c index 705dcb1..88aa9c1 100644 --- a/common/hooklib/config.c +++ b/common/hooklib/config.c @@ -9,6 +9,7 @@ #include "hooklib/dvd.h" #include "hooklib/y3.h" #include "hooklib/y3-dll.h" +#include "util/io-path.h" void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename) { @@ -158,12 +159,13 @@ void y3_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"y3io", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"y3io", + L"path", + L"SEGATOOLS_Y3IO_PATH", + L"y3io.dll", filename); } @@ -243,4 +245,4 @@ void y3_config_load( filename); wcstombs(cfg->target_code_printer, tmpstr, sizeof(cfg->target_code_printer) - 1); -} \ No newline at end of file +} diff --git a/common/util/io-path.c b/common/util/io-path.c new file mode 100644 index 0000000..03a5df3 --- /dev/null +++ b/common/util/io-path.c @@ -0,0 +1,203 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "util/dprintf.h" +#include "util/io-path.h" + +static bool io_path_expand( + wchar_t *out, + size_t out_count, + const wchar_t *path, + const wchar_t *source); +static bool io_path_from_root( + wchar_t *out, + size_t out_count, + const wchar_t *root_filename); +static bool io_path_is_separator(wchar_t ch); + +bool io_path_config_load( + wchar_t *out, + size_t out_count, + const wchar_t *section, + const wchar_t *key, + const wchar_t *env_name, + const wchar_t *root_filename, + const wchar_t *filename) +{ + wchar_t path[MAX_PATH]; + DWORD count; + + assert(out != NULL); + assert(out_count > 0); + assert(section != NULL); + assert(key != NULL); + assert(filename != NULL); + + out[0] = L'\0'; + + count = GetPrivateProfileStringW( + section, + key, + L"", + path, + _countof(path), + filename); + + if (count >= _countof(path) - 1 && path[0] != L'\0') { + dprintf("IO path: INI value [%S] %S may be truncated " + "(exceeds %d characters)\n", + section, + key, + (int) _countof(path) - 1); + } + + if (path[0] != L'\0') { + return io_path_expand(out, out_count, path, key); + } + + if (env_name != NULL) { + count = GetEnvironmentVariableW(env_name, path, _countof(path)); + + if (count >= _countof(path)) { + dprintf("IO path: Environment variable too long: %S\n", env_name); + + return false; + } + + if (count != 0 && path[0] != L'\0') { + return io_path_expand(out, out_count, path, env_name); + } + } + + return io_path_from_root(out, out_count, root_filename); +} + +static bool io_path_expand( + wchar_t *out, + size_t out_count, + const wchar_t *path, + const wchar_t *source) +{ + DWORD expanded; + + assert(out != NULL); + assert(out_count > 0); + assert(path != NULL); + assert(source != NULL); + + expanded = ExpandEnvironmentStringsW(path, out, (DWORD) out_count); + + if (expanded == 0) { + dprintf("IO path: Failed to expand path from %S: %lx\n", + source, + GetLastError()); + out[0] = L'\0'; + + return false; + } + + if (expanded > out_count) { + dprintf("IO path: Expanded path from %S is too long: %S\n", + source, + path); + out[0] = L'\0'; + + return false; + } + + return true; +} + +static bool io_path_from_root( + wchar_t *out, + size_t out_count, + const wchar_t *root_filename) +{ + wchar_t root[MAX_PATH]; + wchar_t expanded_root[MAX_PATH]; + size_t root_len; + size_t file_len; + DWORD count; + + assert(out != NULL); + assert(out_count > 0); + + if (root_filename == NULL || root_filename[0] == L'\0') { + return false; + } + + count = GetEnvironmentVariableW( + L"SEGATOOLS_IO_ROOT", + root, + _countof(root)); + + if (count >= _countof(root)) { + dprintf("IO path: SEGATOOLS_IO_ROOT is too long\n"); + + return false; + } + + if (count == 0 || root[0] == L'\0') { + return false; + } + + if (!io_path_expand( + expanded_root, + _countof(expanded_root), + root, + L"SEGATOOLS_IO_ROOT")) { + return false; + } + + root_len = wcslen(expanded_root); + file_len = wcslen(root_filename); + + if (root_len == 0) { + return false; + } + + if (root_len + file_len + 2 > out_count) { + dprintf("IO path: SEGATOOLS_IO_ROOT path is too long: %S\\%S\n", + expanded_root, + root_filename); + + return false; + } + + wcscpy_s(out, out_count, expanded_root); + + if (!io_path_is_separator(out[root_len - 1])) { + out[root_len++] = L'\\'; + out[root_len] = L'\0'; + } + + wcscat_s(out, out_count, root_filename); + + /* The SEGATOOLS_IO_ROOT fallback is broadcast to every hook at once, so a + single global setting is shared by games that may not each ship an IO + DLL in that directory. Unlike an explicit INI/env path (direct user + intent, allowed to fail loudly at load time), a synthesized root path + that does not exist should quietly fall back to the built-in IO + implementation instead of aborting hook startup. */ + if (GetFileAttributesW(out) == INVALID_FILE_ATTRIBUTES) { + dprintf("IO path: SEGATOOLS_IO_ROOT DLL not found, " + "using built-in IO: %S\n", + out); + out[0] = L'\0'; + + return false; + } + + return true; +} + +static bool io_path_is_separator(wchar_t ch) +{ + return ch == L'\\' || ch == L'/'; +} diff --git a/common/util/io-path.h b/common/util/io-path.h new file mode 100644 index 0000000..ce5694d --- /dev/null +++ b/common/util/io-path.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include +#include + +bool io_path_config_load( + wchar_t *out, + size_t out_count, + const wchar_t *section, + const wchar_t *key, + const wchar_t *env_name, + const wchar_t *root_filename, + const wchar_t *filename); diff --git a/common/util/meson.build b/common/util/meson.build index a0150a7..4a060dd 100644 --- a/common/util/meson.build +++ b/common/util/meson.build @@ -21,6 +21,8 @@ util_lib = static_library( 'fg-detect.h', 'get_function_ordinal.c', 'get_function_ordinal.h', + 'io-path.c', + 'io-path.h', 'lib.c', 'lib.h', 'slurp.c', diff --git a/dist/apm3/segatools.ini b/dist/apm3/segatools.ini index 502cea9..2df4cc9 100644 --- a/dist/apm3/segatools.ini +++ b/dist/apm3/segatools.ini @@ -133,11 +133,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [apm3io] ; To use a custom APM3 IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad input. +; If empty, SEGATOOLS_APM3IO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\apm3io.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/carol/segatools.ini b/dist/carol/segatools.ini index 7432db7..26de2f4 100644 --- a/dist/carol/segatools.ini +++ b/dist/carol/segatools.ini @@ -97,6 +97,8 @@ dpiAware=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index c8e760c..d5ef905 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -136,11 +136,15 @@ controllerLedOutputOpeNITHM=0 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [chuniio] ; To use a custom Chunithm IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_CHUNIIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\chuniio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index fd70d43..09a5778 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -162,15 +162,20 @@ controllerLedOutputOpeNITHM=0 [aimeio] ; To use a custom card reader IO DLL (x64) enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [chuniio] ; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL. ; (will use chu2to3 engine internally) +; If empty, SEGATOOLS_CHUNIIO_PATH can provide this path. ;path= ; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs. ; x86 chuniio to path32, x64 to path64. Both are necessary. +; If empty, SEGATOOLS_CHUNIIO_PATH32 and SEGATOOLS_CHUNIIO_PATH64 are used if set. +; Otherwise SEGATOOLS_IO_ROOT\chuniio_x86.dll and SEGATOOLS_IO_ROOT\chuniio_x64.dll are used. ;path32= ;path64= diff --git a/dist/cm/segatools.ini b/dist/cm/segatools.ini index d91fc51..946d824 100644 --- a/dist/cm/segatools.ini +++ b/dist/cm/segatools.ini @@ -103,6 +103,8 @@ printerOutPath="DEVICE\print" [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index fa03ab9..a730f06 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -108,11 +108,15 @@ dpiAware=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [cxbio] ; To use a custom crossbeats REV. DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_CXBIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\cxbio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/diva/segatools.ini b/dist/diva/segatools.ini index e37d2c4..c92d0df 100644 --- a/dist/diva/segatools.ini +++ b/dist/diva/segatools.ini @@ -98,11 +98,15 @@ dpiAware=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [divaio] ; To use a custom Project DIVA Arcade IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad/wheel input. +; If empty, SEGATOOLS_DIVAIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\divaio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/ekt/segatools_satellite.ini b/dist/ekt/segatools_satellite.ini index a07a2b2..d141b52 100644 --- a/dist/ekt/segatools_satellite.ini +++ b/dist/ekt/segatools_satellite.ini @@ -114,16 +114,22 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [ektio] ; To use a custom Eiketsu Taisen IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard/gamepad input. +; If empty, SEGATOOLS_EKTIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\ektio.dll. path= [y3io] ; To use a custom Y3 IO DLL enter its path here. ; Leave empty if you want to use ... TBA ... +; If empty, SEGATOOLS_Y3IO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\y3io.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/ekt/segatools_terminal.ini b/dist/ekt/segatools_terminal.ini index 71c0195..0c019f8 100644 --- a/dist/ekt/segatools_terminal.ini +++ b/dist/ekt/segatools_terminal.ini @@ -101,11 +101,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [ektio] ; To use a custom Eiketsu Taisen IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard/gamepad input. +; If empty, SEGATOOLS_EKTIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\ektio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index b1739f7..a901347 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -134,11 +134,15 @@ rotate180=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [fgoio] ; To use a custom Fate/Grand Order Arcade IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad input. +; If empty, SEGATOOLS_FGOIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\fgoio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index 0b8c083..2268d27 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -125,11 +125,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [idacio] ; To use a custom Initial D THE ARCADE IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad/wheel input. +; If empty, SEGATOOLS_IDACIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\idacio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/idz/segatools.ini b/dist/idz/segatools.ini index d27d992..20f02db 100644 --- a/dist/idz/segatools.ini +++ b/dist/idz/segatools.ini @@ -125,11 +125,15 @@ dpiAware=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [idzio] ; To use a custom Initial D Zero IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad/wheel input. +; If empty, SEGATOOLS_IDZIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\idzio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/kemono/segatools.ini b/dist/kemono/segatools.ini index 143b442..d4c2ea1 100644 --- a/dist/kemono/segatools.ini +++ b/dist/kemono/segatools.ini @@ -123,11 +123,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [kemonoio] ; To use a custom Kemono IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_KEMONOIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\kemonoio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/mai2/segatools.ini b/dist/mai2/segatools.ini index c1aaaa4..9a06bcb 100644 --- a/dist/mai2/segatools.ini +++ b/dist/mai2/segatools.ini @@ -112,11 +112,15 @@ targetAssembly= [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [mai2io] ; To use a custom maimai DX IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_MAI2IO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\mai2io.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index d866a6b..4c61e04 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -109,11 +109,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [mercuryio] ; To use a custom WACCA IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_MERCURYIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\mercuryio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index dc72f69..f28dc32 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -153,11 +153,15 @@ controllerLedOutputSerial=0 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [mu3io] ; To use a custom O.N.G.E.K.I. IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard/gamepad input. +; If empty, SEGATOOLS_MU3IO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\mu3io.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/sekito/segatools_satellite.ini b/dist/sekito/segatools_satellite.ini index 0dd89c6..af220aa 100644 --- a/dist/sekito/segatools_satellite.ini +++ b/dist/sekito/segatools_satellite.ini @@ -138,16 +138,22 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [sekitoio] ; To use a custom Eiketsu Taisen IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard/gamepad input. +; If empty, SEGATOOLS_SEKITOIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\sekitoio.dll. path= [y3io] ; To use a custom Y3 IO DLL enter its path here. ; Leave empty if you want to use ... TBA ... +; If empty, SEGATOOLS_Y3IO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\y3io.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/sekito/segatools_terminal.ini b/dist/sekito/segatools_terminal.ini index fbd0455..791b77f 100644 --- a/dist/sekito/segatools_terminal.ini +++ b/dist/sekito/segatools_terminal.ini @@ -123,11 +123,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [sekitoio] ; To use a custom Eiketsu Taisen IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard/gamepad input. +; If empty, SEGATOOLS_SEKITOIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\sekitoio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/swdc/segatools.ini b/dist/swdc/segatools.ini index 1d43e50..e2924dc 100644 --- a/dist/swdc/segatools.ini +++ b/dist/swdc/segatools.ini @@ -92,11 +92,15 @@ enable=1 [aimeio] ; To use a custom card reader IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. +; If empty, SEGATOOLS_AIMEIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\aimeio.dll. path= [swdcio] ; To use a custom SEGA World Drivers Championship DLL enter its path here. ; Leave empty if you want to use Segatools built-in gamepad/wheel input. +; If empty, SEGATOOLS_SWDCIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\swdcio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/dist/tokyo/segatools.ini b/dist/tokyo/segatools.ini index d48727f..0b9e461 100644 --- a/dist/tokyo/segatools.ini +++ b/dist/tokyo/segatools.ini @@ -106,6 +106,8 @@ enable=1 ; To use a custom Mario & Sonic at the Tokyo 2020 Olympics Arcade IO DLL enter ; its path here. Leave empty if you want to use Segatools built-in keyboard/ ; gamepad input. +; If empty, SEGATOOLS_TOKYOIO_PATH is used if set, followed by +; SEGATOOLS_IO_ROOT\tokyoio.dll. path= ; ----------------------------------------------------------------------------- diff --git a/doc/config/common.md b/doc/config/common.md index eb6e789..e6a13e7 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -17,6 +17,61 @@ Then you can copy `segatools.ini` to `another_config.ini` but with different dns set SEGATOOLS_CONFIG_PATH=.\another_config.ini ``` +## IO DLL path resolution + +Custom IO DLL paths are resolved in this order: + +1. The section-specific INI value, such as `[mai2io] path=`. +2. The section-specific environment variable, such as `SEGATOOLS_MAI2IO_PATH`. +3. `SEGATOOLS_IO_ROOT` joined with the default IO DLL filename, such as + `%SEGATOOLS_IO_ROOT%\mai2io.dll`. +4. Empty path, which keeps the built-in IO implementation. + +INI paths and environment-variable paths support Windows environment variable +expansion, so an INI entry like this is valid: + +```ini +[mai2io] +path=%SEGATOOLS_IO_ROOT%\mai2io.dll +``` + +Supported IO environment variables: + +| INI section | Direct environment variable | `SEGATOOLS_IO_ROOT` filename | +| --- | --- | --- | +| `[aimeio]` | `SEGATOOLS_AIMEIO_PATH` | `aimeio.dll` | +| `[apm3io]` | `SEGATOOLS_APM3IO_PATH` | `apm3io.dll` | +| `[carolio]` | `SEGATOOLS_CAROLIO_PATH` | `carolio.dll` | +| `[chuniio]` | `SEGATOOLS_CHUNIIO_PATH` | `chuniio.dll` \* | +| `[cmio]` | `SEGATOOLS_CMIO_PATH` | `cmio.dll` | +| `[cxbio]` | `SEGATOOLS_CXBIO_PATH` | `cxbio.dll` | +| `[divaio]` | `SEGATOOLS_DIVAIO_PATH` | `divaio.dll` | +| `[ektio]` | `SEGATOOLS_EKTIO_PATH` | `ektio.dll` | +| `[fgoio]` | `SEGATOOLS_FGOIO_PATH` | `fgoio.dll` | +| `[idacio]` | `SEGATOOLS_IDACIO_PATH` | `idacio.dll` | +| `[idzio]` | `SEGATOOLS_IDZIO_PATH` | `idzio.dll` | +| `[kemonoio]` | `SEGATOOLS_KEMONOIO_PATH` | `kemonoio.dll` | +| `[mai2io]` | `SEGATOOLS_MAI2IO_PATH` | `mai2io.dll` | +| `[mercuryio]` | `SEGATOOLS_MERCURYIO_PATH` | `mercuryio.dll` | +| `[mu3io]` | `SEGATOOLS_MU3IO_PATH` | `mu3io.dll` | +| `[sekitoio]` | `SEGATOOLS_SEKITOIO_PATH` | `sekitoio.dll` | +| `[swdcio]` | `SEGATOOLS_SWDCIO_PATH` | `swdcio.dll` | +| `[tokyoio]` | `SEGATOOLS_TOKYOIO_PATH` | `tokyoio.dll` | +| `[y3io]` | `SEGATOOLS_Y3IO_PATH` | `y3io.dll` | + +\* The `%SEGATOOLS_IO_ROOT%\chuniio.dll` fallback applies to the +single-32-bit-DLL Chunithm hook (`chunihook`) only. Chunithm NEW and later +(`chusanhook`) resolve the single-DLL `[chuniio] path=` / `SEGATOOLS_CHUNIIO_PATH` +from the INI value or environment variable only, with no `SEGATOOLS_IO_ROOT` +default; those builds use the `path32`/`path64` mechanism below for their +`SEGATOOLS_IO_ROOT` defaults. + +For Chunithm NEW and later hooks that use separate 32-bit and 64-bit IO DLLs, +`[chuniio] path32=` maps to `SEGATOOLS_CHUNIIO_PATH32` and +`[chuniio] path64=` maps to `SEGATOOLS_CHUNIIO_PATH64`. When only +`SEGATOOLS_IO_ROOT` is set, these hooks look for `chuniio_x86.dll` and +`chuniio_x64.dll`. + ## `[aimeio]` Controls the card reader driver. @@ -25,6 +80,8 @@ Controls the card reader driver. Specify a path for a third-party card reader driver DLL. Default is empty (use built-in emulation based on text files and keyboard input). +If empty, `SEGATOOLS_AIMEIO_PATH` is used if set, followed by +`%SEGATOOLS_IO_ROOT%\aimeio.dll`. In previous versions of Segatools this was accomplished by replacing the AIMEIO.DLL file that came with Segatools. Segatools no longer ships with a @@ -812,4 +869,4 @@ This is a file that will be set to the content of what would be written to the ` This allows whatever executed the game process to react what should happen next (System Test Mode selected, network delivery completed, ...) without requiring admin permissions. -The file is deleted on startup of segatools. \ No newline at end of file +The file is deleted on startup of segatools. diff --git a/games/apm3hook/config.c b/games/apm3hook/config.c index 6b0b5cd..c730dc2 100644 --- a/games/apm3hook/config.c +++ b/games/apm3hook/config.c @@ -10,6 +10,7 @@ #include "apm3hook/config.h" #include "platform/config.h" +#include "util/io-path.h" void apm3_dll_config_load( struct apm3_dll_config *cfg, @@ -18,12 +19,13 @@ void apm3_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"apm3io", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"apm3io", + L"path", + L"SEGATOOLS_APM3IO_PATH", + L"apm3io.dll", filename); } diff --git a/games/carolhook/config.c b/games/carolhook/config.c index 9f2ef2d..42283a5 100644 --- a/games/carolhook/config.c +++ b/games/carolhook/config.c @@ -13,6 +13,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void carol_dll_config_load( struct carol_dll_config *cfg, @@ -21,12 +22,13 @@ void carol_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"carolio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"carolio", + L"path", + L"SEGATOOLS_CAROLIO_PATH", + L"carolio.dll", filename); } diff --git a/games/chunihook/config.c b/games/chunihook/config.c index d711fec..67e0bb0 100644 --- a/games/chunihook/config.c +++ b/games/chunihook/config.c @@ -19,6 +19,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void chuni_dll_config_load( struct chuni_dll_config *cfg, @@ -27,12 +28,13 @@ void chuni_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"chuniio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"chuniio", + L"path", + L"SEGATOOLS_CHUNIIO_PATH", + L"chuniio.dll", filename); } diff --git a/games/chusanhook/config.c b/games/chusanhook/config.c index 691e8f7..a3c2126 100644 --- a/games/chusanhook/config.c +++ b/games/chusanhook/config.c @@ -12,6 +12,7 @@ #include "platform/config.h" #include "chusanhook/config.h" +#include "util/io-path.h" // Check windows #if _WIN32 || _WIN64 @@ -42,32 +43,34 @@ void chuni_dll_config_load( // path32 for 32bit, path64 for 64bit // path for 32bit only dlls (internal chu2to3 engine) - GetPrivateProfileStringW( - L"chuniio", - L"path", - L"", + if (io_path_config_load( cfg->path, _countof(cfg->path), - filename); - if (cfg->path[0] != L'\0') { + L"chuniio", + L"path", + L"SEGATOOLS_CHUNIIO_PATH", + NULL, + filename)) { cfg->chu2to3 = 1; } else { cfg->chu2to3 = 0; #if defined(ENV32BIT) - GetPrivateProfileStringW( - L"chuniio", - L"path32", - L"", - cfg->path, - _countof(cfg->path), - filename); + io_path_config_load( + cfg->path, + _countof(cfg->path), + L"chuniio", + L"path32", + L"SEGATOOLS_CHUNIIO_PATH32", + L"chuniio_x86.dll", + filename); #elif defined(ENV64BIT) - GetPrivateProfileStringW( - L"chuniio", - L"path64", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"chuniio", + L"path64", + L"SEGATOOLS_CHUNIIO_PATH64", + L"chuniio_x64.dll", filename); #else #error "Unknown environment" diff --git a/games/cmhook/config.c b/games/cmhook/config.c index c69a5b9..96197a3 100644 --- a/games/cmhook/config.c +++ b/games/cmhook/config.c @@ -10,6 +10,7 @@ #include "cmhook/config.h" #include "platform/config.h" +#include "util/io-path.h" void cm_dll_config_load( struct cm_dll_config *cfg, @@ -18,12 +19,13 @@ void cm_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"cmio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"cmio", + L"path", + L"SEGATOOLS_CMIO_PATH", + L"cmio.dll", filename); } diff --git a/games/cxbhook/config.c b/games/cxbhook/config.c index 8a2d6fb..9294d1e 100644 --- a/games/cxbhook/config.c +++ b/games/cxbhook/config.c @@ -19,6 +19,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void cxb_dll_config_load( struct cxb_dll_config *cfg, @@ -27,12 +28,13 @@ void cxb_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"cxbio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"cxbio", + L"path", + L"SEGATOOLS_CXBIO_PATH", + L"cxbio.dll", filename); } @@ -69,4 +71,4 @@ void cxb_hook_config_load( cxb_dll_config_load(&cfg->dll, filename); revio_config_load(&cfg->revio, filename); led_config_load(&cfg->led, filename); -} \ No newline at end of file +} diff --git a/games/divahook/config.c b/games/divahook/config.c index 45d1968..243fa05 100644 --- a/games/divahook/config.c +++ b/games/divahook/config.c @@ -15,6 +15,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void diva_dll_config_load( struct diva_dll_config *cfg, @@ -23,12 +24,13 @@ void diva_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"divaio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"divaio", + L"path", + L"SEGATOOLS_DIVAIO_PATH", + L"divaio.dll", filename); } diff --git a/games/ekthook/config.c b/games/ekthook/config.c index e98cafe..4b6c83f 100644 --- a/games/ekthook/config.c +++ b/games/ekthook/config.c @@ -11,6 +11,7 @@ #include "hooklib/config.h" #include "platform/config.h" +#include "util/io-path.h" void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { @@ -80,12 +81,13 @@ void ekt_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"ektio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"ektio", + L"path", + L"SEGATOOLS_EKTIO_PATH", + L"ektio.dll", filename); } diff --git a/games/fgohook/config.c b/games/fgohook/config.c index b5b1d24..8c400dc 100644 --- a/games/fgohook/config.c +++ b/games/fgohook/config.c @@ -10,6 +10,7 @@ #include "fgohook/config.h" #include "platform/config.h" +#include "util/io-path.h" void fgo_dll_config_load( struct fgo_dll_config *cfg, @@ -18,12 +19,13 @@ void fgo_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"fgoio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"fgoio", + L"path", + L"SEGATOOLS_FGOIO_PATH", + L"fgoio.dll", filename); } diff --git a/games/idachook/config.c b/games/idachook/config.c index b96f1bf..c180d6f 100644 --- a/games/idachook/config.c +++ b/games/idachook/config.c @@ -13,6 +13,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) @@ -59,12 +60,13 @@ void idac_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"idacio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"idacio", + L"path", + L"SEGATOOLS_IDACIO_PATH", + L"idacio.dll", filename); } diff --git a/games/idzhook/config.c b/games/idzhook/config.c index 6bbc0ed..e6050d4 100644 --- a/games/idzhook/config.c +++ b/games/idzhook/config.c @@ -18,6 +18,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) { @@ -63,12 +64,13 @@ void idz_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"idzio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"idzio", + L"path", + L"SEGATOOLS_IDZIO_PATH", + L"idzio.dll", filename); } diff --git a/games/kemonohook/config.c b/games/kemonohook/config.c index bd539dd..b62d0a2 100644 --- a/games/kemonohook/config.c +++ b/games/kemonohook/config.c @@ -12,6 +12,7 @@ #include "kemonohook/config.h" #include "platform/config.h" +#include "util/io-path.h" // Check windows #if _WIN32 || _WIN64 @@ -41,12 +42,13 @@ void kemono_dll_config_load( // Always empty, due to amdaemon being 64 bit in 32 bit mode memset(cfg->path, 0, sizeof(cfg->path)); #elif defined(ENV64BIT) - GetPrivateProfileStringW( - L"kemonoio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"kemonoio", + L"path", + L"SEGATOOLS_KEMONOIO_PATH", + L"kemonoio.dll", filename); #else #error "Unknown environment" diff --git a/games/mai2hook/config.c b/games/mai2hook/config.c index 5435ada..7681cb1 100644 --- a/games/mai2hook/config.c +++ b/games/mai2hook/config.c @@ -10,6 +10,7 @@ #include "mai2hook/config.h" #include "platform/config.h" +#include "util/io-path.h" void mai2_dll_config_load( struct mai2_dll_config *cfg, @@ -18,12 +19,13 @@ void mai2_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"mai2io", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"mai2io", + L"path", + L"SEGATOOLS_MAI2IO_PATH", + L"mai2io.dll", filename); } diff --git a/games/mercuryhook/config.c b/games/mercuryhook/config.c index e781273..9964cf1 100644 --- a/games/mercuryhook/config.c +++ b/games/mercuryhook/config.c @@ -11,6 +11,7 @@ #include "mercuryhook/config.h" #include "platform/config.h" +#include "util/io-path.h" void mercury_dll_config_load( struct mercury_dll_config *cfg, @@ -19,12 +20,13 @@ void mercury_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"mercuryio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"mercuryio", + L"path", + L"SEGATOOLS_MERCURYIO_PATH", + L"mercuryio.dll", filename); } diff --git a/games/mu3hook/config.c b/games/mu3hook/config.c index 6c52446..7f62b18 100644 --- a/games/mu3hook/config.c +++ b/games/mu3hook/config.c @@ -12,6 +12,7 @@ #include "mu3hook/config.h" #include "platform/config.h" +#include "util/io-path.h" void mu3_dll_config_load( struct mu3_dll_config *cfg, @@ -20,12 +21,13 @@ void mu3_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"mu3io", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"mu3io", + L"path", + L"SEGATOOLS_MU3IO_PATH", + L"mu3io.dll", filename); } diff --git a/games/sekitohook/config.c b/games/sekitohook/config.c index 4aae6cb..0798c86 100644 --- a/games/sekitohook/config.c +++ b/games/sekitohook/config.c @@ -12,6 +12,7 @@ #include "hooklib/config.h" #include "platform/config.h" +#include "util/io-path.h" void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { @@ -81,12 +82,13 @@ void sekito_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"sekitoio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"sekitoio", + L"path", + L"SEGATOOLS_SEKITOIO_PATH", + L"sekitoio.dll", filename); } diff --git a/games/swdchook/config.c b/games/swdchook/config.c index e64654e..5db2819 100644 --- a/games/swdchook/config.c +++ b/games/swdchook/config.c @@ -13,6 +13,7 @@ #include "platform/config.h" #include "platform/platform.h" +#include "util/io-path.h" void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename) @@ -59,12 +60,13 @@ void swdc_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"swdcio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"swdcio", + L"path", + L"SEGATOOLS_SWDCIO_PATH", + L"swdcio.dll", filename); } diff --git a/games/tokyohook/config.c b/games/tokyohook/config.c index 3ab387a..748611e 100644 --- a/games/tokyohook/config.c +++ b/games/tokyohook/config.c @@ -12,6 +12,7 @@ #include "platform/config.h" #include "tokyohook/config.h" +#include "util/io-path.h" void tokyo_dll_config_load( struct tokyo_dll_config *cfg, @@ -19,12 +20,13 @@ void tokyo_dll_config_load( assert(cfg != NULL); assert(filename != NULL); - GetPrivateProfileStringW( - L"tokyoio", - L"path", - L"", + io_path_config_load( cfg->path, _countof(cfg->path), + L"tokyoio", + L"path", + L"SEGATOOLS_TOKYOIO_PATH", + L"tokyoio.dll", filename); }