#include #include "launcher/launcher.hpp" #include "loader/loader.hpp" #include "loader/component_loader.hpp" #include "game/game.hpp" #include #include #include DECLSPEC_NORETURN void WINAPI exit_hook(const int code) { component_loader::pre_destroy(); exit(code); } BOOL WINAPI system_parameters_info_a(const UINT uiAction, const UINT uiParam, const PVOID pvParam, const UINT fWinIni) { component_loader::post_unpack(); return SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni); } FARPROC WINAPI get_proc_address(const HMODULE hModule, const LPCSTR lpProcName) { if (lpProcName == "GlobalMemoryStatusEx"s) { component_loader::post_unpack(); } return GetProcAddress(hModule, lpProcName); } launcher::mode detect_mode_from_arguments() { if (utils::flags::has_flag("dedicated")) { return launcher::mode::server; } if (utils::flags::has_flag("multiplayer")) { return launcher::mode::multiplayer; } if (utils::flags::has_flag("singleplayer")) { return launcher::mode::singleplayer; } return launcher::mode::none; } FARPROC load_binary(const launcher::mode mode) { loader loader; utils::nt::library self; loader.set_import_resolver([self](const std::string& library, const std::string& function) -> void* { if (library == "steam_api64.dll") { return self.get_proc(function); } else if (function == "ExitProcess") { return exit_hook; } else if (function == "SystemParametersInfoA") { return system_parameters_info_a; } else if (function == "GetProcAddress") { return get_proc_address; } return component_loader::load_import(library, function); }); std::string binary; switch (mode) { case launcher::mode::server: case launcher::mode::multiplayer: binary = "h1_mp64_ship.exe"; break; case launcher::mode::singleplayer: binary = "h1_sp64_ship.exe"; break; case launcher::mode::none: default: throw std::runtime_error("Invalid game mode!"); } std::string data; if (!utils::io::read_file(binary, &data)) { throw std::runtime_error(utils::string::va( "Failed to read game binary (%s)!\nPlease copy the h1-mod.exe into your Call of Duty: Modern Warfare Remastered installation folder and run it from there.", binary.data())); } return loader.load_library(binary); } void remove_crash_file() { utils::io::remove_file("__h1Exe"); } void enable_dpi_awareness() { const utils::nt::library user32{"user32.dll"}; const auto set_dpi = user32 ? user32.get_proc("SetProcessDpiAwarenessContext") : nullptr; if (set_dpi) { set_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); } } void limit_parallel_dll_loading() { const utils::nt::library self; const auto registry_path = R"(Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)" + self. get_name(); HKEY key = nullptr; if (RegCreateKeyA(HKEY_LOCAL_MACHINE, registry_path.data(), &key) == ERROR_SUCCESS) { RegCloseKey(key); } key = nullptr; if (RegOpenKeyExA( HKEY_LOCAL_MACHINE, registry_path.data(), 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) { return; } DWORD value = 1; RegSetValueExA(key, "MaxLoaderThreads", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); RegCloseKey(key); } int main() { FARPROC entry_point; enable_dpi_awareness(); // This requires admin privilege, but I suppose many // people will start with admin rights if it crashes. limit_parallel_dll_loading(); srand(uint32_t(time(nullptr))); { auto premature_shutdown = true; const auto _ = gsl::finally([&premature_shutdown]() { if (premature_shutdown) { component_loader::pre_destroy(); } }); try { remove_crash_file(); if (!component_loader::post_start()) return 0; auto mode = detect_mode_from_arguments(); if (mode == launcher::mode::none) { const launcher launcher; mode = launcher.run(); if (mode == launcher::mode::none) return 0; } game::environment::set_mode(mode); entry_point = load_binary(mode); if (!entry_point) { throw std::runtime_error("Unable to load binary into memory"); } if (!component_loader::post_load()) return 0; premature_shutdown = false; } catch (std::exception& e) { MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); return 1; } } return static_cast(entry_point()); } int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int) { return main(); }