diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 7a6c2774..1a9c07e7 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -229,7 +229,8 @@ set(UNLEASHED_RECOMP_CXX_SOURCES "app.cpp" "exports.cpp" "main.cpp" - "misc_impl.cpp" + "misc_impl.cpp" + "preload_executable.cpp" "sdl_listener.cpp" "stdafx.cpp" "version.cpp" diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index a55c0181..08ddb66c 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -193,6 +194,9 @@ int main(int argc, char *argv[]) os::logger::Init(); + PreloadContext preloadContext; + preloadContext.PreloadExecutable(); + bool forceInstaller = false; bool forceDLCInstaller = false; const char *sdlVideoDriver = nullptr; diff --git a/UnleashedRecomp/preload_executable.cpp b/UnleashedRecomp/preload_executable.cpp new file mode 100644 index 00000000..6458abb9 --- /dev/null +++ b/UnleashedRecomp/preload_executable.cpp @@ -0,0 +1,104 @@ +#include "preload_executable.h" +#include + +// Code from Zelda 64: Recompiled +// https://github.com/Zelda64Recomp/Zelda64Recomp/blob/91db87632c2bfb6995ef1554ec71b11977c621f8/src/main/main.cpp#L440-L514 + +PreloadContext::~PreloadContext() +{ +#ifdef _WIN32 + if (preloaded) + { + VirtualUnlock(view, size); + CloseHandle(mappingHandle); + CloseHandle(handle); + } +#endif +} + +void PreloadContext::PreloadExecutable() +{ +#ifdef _WIN32 + wchar_t moduleName[MAX_PATH]; + GetModuleFileNameW(NULL, moduleName, MAX_PATH); + + handle = CreateFileW(moduleName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (handle == INVALID_HANDLE_VALUE) + { + LOG_ERROR("Failed to load executable into memory!"); + *this = {}; + return; + } + + LARGE_INTEGER moduleSize; + if (!GetFileSizeEx(handle, &moduleSize)) + { + LOG_ERROR("Failed to get size of executable!"); + CloseHandle(handle); + *this = {}; + return; + } + + size = moduleSize.QuadPart; + + mappingHandle = CreateFileMappingW(handle, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (mappingHandle == nullptr) + { + LOG_ERROR("Failed to create file mapping of executable!"); + CloseHandle(handle); + *this = {}; + return; + } + + view = MapViewOfFile(mappingHandle, FILE_MAP_READ, 0, 0, 0); + if (view == nullptr) + { + LOG_ERROR("Failed to map view of of executable!"); + CloseHandle(mappingHandle); + CloseHandle(handle); + *this = {}; + return; + } + + DWORD pid = GetCurrentProcessId(); + HANDLE processHandle = OpenProcess(PROCESS_SET_QUOTA | PROCESS_QUERY_INFORMATION, FALSE, pid); + if (processHandle == nullptr) + { + LOG_ERROR("Failed to open own process!"); + CloseHandle(mappingHandle); + CloseHandle(handle); + *this = {}; + return; + } + + SIZE_T minimumSetSize, maximumSetSize; + if (!GetProcessWorkingSetSize(processHandle, &minimumSetSize, &maximumSetSize)) + { + LOG_ERROR("Failed to get working set size!"); + CloseHandle(mappingHandle); + CloseHandle(handle); + *this = {}; + return; + } + + if (!SetProcessWorkingSetSize(processHandle, minimumSetSize + size, maximumSetSize + size)) + { + LOG_ERROR("Failed to set working set size!"); + CloseHandle(mappingHandle); + CloseHandle(handle); + *this = {}; + return; + } + + if (VirtualLock(view, size) == 0) + { + LOGF_ERROR("Failed to lock view of executable! (Error: 0x{:X})\n", GetLastError()); + CloseHandle(mappingHandle); + CloseHandle(handle); + *this = {}; + return; + } + + preloaded = true; +#endif +} diff --git a/UnleashedRecomp/preload_executable.h b/UnleashedRecomp/preload_executable.h new file mode 100644 index 00000000..5afb2b4e --- /dev/null +++ b/UnleashedRecomp/preload_executable.h @@ -0,0 +1,15 @@ +#pragma once + +struct PreloadContext +{ +#ifdef _WIN32 + HANDLE handle{}; + HANDLE mappingHandle{}; + SIZE_T size{}; + PVOID view{}; + bool preloaded{}; +#endif + + ~PreloadContext(); + void PreloadExecutable(); +};