#include #include #include #include #include #include #include #include #include #include #include #include "windowsPlatform.hpp" extern void start_console(); const auto CONSOLE_TITLE = L"Gakumas Localify"; std::filesystem::path gakumasLocalPath = "./gakumas-local"; std::filesystem::path ProgramConfigJson = gakumasLocalPath / "config.json"; std::filesystem::path ConfigJson = gakumasLocalPath / "localizationConfig.json"; bool g_has_config_file = false; bool g_enable_console = true; bool g_useRemoteAssets = false; bool g_useAPIAssets = false; std::string g_remoteResourceUrl = ""; std::string g_useAPIAssetsURL = ""; namespace { void create_debug_console() { AllocConsole(); // open stdout stream auto _ = freopen("CONOUT$", "w+t", stdout); _ = freopen("CONOUT$", "w", stderr); _ = freopen("CONIN$", "r", stdin); SetConsoleTitleW(CONSOLE_TITLE); // set this to avoid turn japanese texts into question mark SetConsoleOutputCP(65001); std::locale::global(std::locale("")); wprintf(L"%ls Loaded! - By chinosk\n", CONSOLE_TITLE); } } void readProgramConfig() { std::vector dicts{}; std::ifstream config_stream{ ProgramConfigJson }; if (!config_stream.is_open()) return; rapidjson::IStreamWrapper wrapper{ config_stream }; rapidjson::Document document; document.ParseStream(wrapper); if (!document.HasParseError()) { g_has_config_file = true; if (document.HasMember("enableConsole")) { g_enable_console = document["enableConsole"].GetBool(); } if (document.HasMember("useRemoteAssets")) { g_useRemoteAssets = document["useRemoteAssets"].GetBool(); } if (document.HasMember("transRemoteZipUrl")) { g_remoteResourceUrl = document["transRemoteZipUrl"].GetString(); } if (document.HasMember("useAPIAssets")) { g_useAPIAssets = document["useAPIAssets"].GetBool(); } if (document.HasMember("useAPIAssetsURL")) { g_useAPIAssetsURL = document["useAPIAssetsURL"].GetString(); } } config_stream.close(); } LONG WINAPI AddressExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) { // Check if the exception is an access violation if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { // Check if the violation address is above 0x7FFFFFFFFFFF if (ExceptionInfo->ExceptionRecord->ExceptionAddress > (PVOID)0x7FFFFFFFFFFF) { // Return EXCEPTION_CONTINUE_EXECUTION to ignore the exception and continue return EXCEPTION_CONTINUE_EXECUTION; } } // For other exceptions or addresses, use the default exception handler return EXCEPTION_CONTINUE_SEARCH; } int __stdcall DllMain(HINSTANCE dllModule, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { AddVectoredExceptionHandler(1, AddressExceptionHandler); // the DMM Launcher set start path to system32 wtf???? std::string module_name; module_name.resize(MAX_PATH); module_name.resize(GetModuleFileName(nullptr, module_name.data(), MAX_PATH)); std::filesystem::path module_path(module_name); // check name if (module_path.filename() != "gakumas.exe") return 1; std::filesystem::current_path( module_path.parent_path() ); readProgramConfig(); if (g_enable_console) create_debug_console(); std::thread init_thread([] { if (g_enable_console) { start_console(); printf("Command: %s\n", GetCommandLineA()); } loadConfig(ConfigJson); initHook(); std::mutex mutex; std::condition_variable cond; std::atomic hookIsReady(false); // 依赖检查游戏版本的指针加载,因此在 hook 完成后再加载翻译数据 std::unique_lock lock(mutex); cond.wait(lock, [&] { return hookIsReady.load(std::memory_order_acquire); }); if (g_enable_console) { auto _ = freopen("CONOUT$", "w+t", stdout); _ = freopen("CONOUT$", "w", stderr); _ = freopen("CONIN$", "r", stdin); } }); init_thread.detach(); } else if (reason == DLL_PROCESS_DETACH) { RemoveVectoredExceptionHandler(AddressExceptionHandler); unInitHook(); } return 1; }