mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-15 03:25:01 -05:00
new proxy loader
- remove bootstrapper dll - add updater exe - remove createthread/loadlibrary calls - and link instead to let windows load it - needs mac port probably?
This commit is contained in:
parent
d72797334f
commit
b47870e7e9
6 changed files with 157 additions and 131 deletions
|
@ -1,71 +0,0 @@
|
|||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <ghc/filesystem.hpp>
|
||||
|
||||
void showError(std::string const& error) {
|
||||
MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR);
|
||||
}
|
||||
|
||||
int loadGeode(PVOID module) {
|
||||
if (!LoadLibraryW(L"Geode.dll")) {
|
||||
auto code = GetLastError();
|
||||
showError("Unable to load Geode (code " + std::to_string(code) + ")");
|
||||
return code;
|
||||
}
|
||||
FreeLibraryAndExitThread(static_cast<HINSTANCE>(module), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI load(PVOID module) {
|
||||
std::array<WCHAR, MAX_PATH> szFileName;
|
||||
GetModuleFileNameW(NULL, szFileName.data(), MAX_PATH);
|
||||
|
||||
const ghc::filesystem::path path(szFileName.data());
|
||||
auto workingDir = path.parent_path();
|
||||
auto updatesDir = workingDir / "geode" / "update";
|
||||
auto resourcesDir = workingDir / "geode" / "resources";
|
||||
|
||||
auto error = std::error_code();
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "Geode.dll", error) && !error) {
|
||||
ghc::filesystem::rename(
|
||||
updatesDir / "Geode.dll",
|
||||
workingDir / "Geode.dll", error
|
||||
);
|
||||
if (error) {
|
||||
showError("Unable to update Geode: Unable to move Geode.dll - " + error.message());
|
||||
return error.value();
|
||||
}
|
||||
}
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "resources", error) && !error) {
|
||||
ghc::filesystem::remove_all(resourcesDir / "geode.loader", error);
|
||||
|
||||
if (error) {
|
||||
showError("Unable to update Geode resources: " + error.message());
|
||||
} else {
|
||||
ghc::filesystem::rename(
|
||||
updatesDir / "resources",
|
||||
resourcesDir / "geode.loader", error
|
||||
);
|
||||
if (error) {
|
||||
showError("Unable to update Geode resources: " + error.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loadGeode(module);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID) {
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
HANDLE handle = CreateThread(NULL, 0, load, module, 0, NULL);
|
||||
if (handle) {
|
||||
CloseHandle(handle);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
|
@ -20,25 +20,23 @@ set_target_properties(ProxyLoader PROPERTIES
|
|||
RUNTIME_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
)
|
||||
add_library(fake-geode-loader SHARED fakeGeode.c)
|
||||
set_target_properties(fake-geode-loader PROPERTIES OUTPUT_NAME "Geode")
|
||||
target_link_libraries(ProxyLoader PRIVATE fake-geode-loader)
|
||||
|
||||
add_library(Bootstrapper SHARED Bootstrapper.cpp)
|
||||
target_compile_features(Bootstrapper PUBLIC cxx_std_17)
|
||||
set_target_properties(Bootstrapper PROPERTIES
|
||||
add_executable(Updater Updater.cpp)
|
||||
target_compile_features(Updater PUBLIC cxx_std_17)
|
||||
set_target_properties(Updater PROPERTIES
|
||||
PREFIX ""
|
||||
OUTPUT_NAME "GeodeBootstrapper"
|
||||
OUTPUT_NAME "GeodeUpdater"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${GEODE_BIN_PATH}/nightly"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${GEODE_BIN_PATH}/nightly"
|
||||
ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${GEODE_BIN_PATH}/nightly"
|
||||
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${GEODE_BIN_PATH}/nightly"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${GEODE_BIN_PATH}/nightly"
|
||||
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${GEODE_BIN_PATH}/nightly"
|
||||
LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${GEODE_BIN_PATH}/nightly"
|
||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${GEODE_BIN_PATH}/nightly"
|
||||
ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${GEODE_BIN_PATH}/nightly"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
|
||||
)
|
||||
target_link_libraries(Bootstrapper PUBLIC ghc_filesystem)
|
||||
target_link_libraries(Updater PUBLIC ghc_filesystem)
|
||||
|
|
79
loader/launcher/windows/Updater.cpp
Normal file
79
loader/launcher/windows/Updater.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include <Windows.h>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <ghc/filesystem.hpp>
|
||||
|
||||
void showError(std::string const& error) {
|
||||
MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::array<WCHAR, MAX_PATH> szFileName;
|
||||
GetModuleFileNameW(NULL, szFileName.data(), MAX_PATH);
|
||||
|
||||
const ghc::filesystem::path path(szFileName.data());
|
||||
auto workingDir = path.parent_path();
|
||||
auto updatesDir = workingDir / "geode" / "update";
|
||||
auto resourcesDir = workingDir / "geode" / "resources";
|
||||
|
||||
// wait for geode.dll to be writable
|
||||
int delay = 10;
|
||||
HANDLE hFile;
|
||||
while ((hFile = CreateFile((workingDir / "Geode.dll").string().c_str(), FILE_GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
|
||||
if (GetLastError() == ERROR_SHARING_VIOLATION) {
|
||||
Sleep(delay);
|
||||
if (delay < 5120)
|
||||
delay *= 2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (hFile)
|
||||
CloseHandle(hFile);
|
||||
else {
|
||||
showError("Unable to update Geode: Geode.dll is open by another process.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto error = std::error_code();
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "Geode.dll", error) && !error) {
|
||||
ghc::filesystem::rename(updatesDir / "Geode.dll", workingDir / "Geode.dll", error);
|
||||
if (error) {
|
||||
showError("Unable to update Geode: Unable to move Geode.dll - " + error.message());
|
||||
return error.value();
|
||||
}
|
||||
}
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "XInput9_1_0.dll", error) && !error) {
|
||||
ghc::filesystem::rename(updatesDir / "XInput9_1_0.dll", workingDir / "XInput9_1_0.dll", error);
|
||||
if (error) {
|
||||
showError("Unable to update Geode: Unable to move XInput9_1_0.dll - " + error.message());
|
||||
return error.value();
|
||||
}
|
||||
}
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "resources", error) && !error) {
|
||||
ghc::filesystem::remove_all(resourcesDir / "geode.loader", error);
|
||||
|
||||
if (error) {
|
||||
showError("Unable to update Geode resources: " + error.message());
|
||||
} else {
|
||||
ghc::filesystem::rename(
|
||||
updatesDir / "resources",
|
||||
resourcesDir / "geode.loader", error
|
||||
);
|
||||
if (error) {
|
||||
showError("Unable to update Geode resources: " + error.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(argc < 2)
|
||||
return 0;
|
||||
|
||||
// restart gd using the provided path
|
||||
ShellExecute(NULL, "open", (workingDir / argv[1]).string().c_str(), "", workingDir.string().c_str(), TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
2
loader/launcher/windows/fakeGeode.c
Normal file
2
loader/launcher/windows/fakeGeode.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include <Windows.h>
|
||||
__declspec(dllexport) DWORD WINAPI loadGeode(void*);
|
|
@ -11,24 +11,16 @@ DWORD XInputGetDSoundAudioDeviceGuids(DWORD user, GUID* render, GUID* capture) {
|
|||
|
||||
#pragma comment(linker, "/export:XInputGetDSoundAudioDeviceGuids=_XInputGetDSoundAudioDeviceGuids")
|
||||
|
||||
DWORD WINAPI load(PVOID _) {
|
||||
if (!LoadLibraryW(L"GeodeBootstrapper.dll")) {
|
||||
char msg[256];
|
||||
sprintf(msg,
|
||||
"Unable to load Geode: Unable to load "
|
||||
"bootstrapper (error code %d)", GetLastError()
|
||||
);
|
||||
MessageBoxA(NULL, msg, "Error Loading Geode", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__declspec(dllimport) DWORD WINAPI loadGeode(void*);
|
||||
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID _) {
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
HANDLE handle = CreateThread(NULL, 0, load, module, 0, NULL);
|
||||
if (handle)
|
||||
CloseHandle(handle);
|
||||
else
|
||||
// Prevents threads from notifying this DLL on creation or destruction.
|
||||
// Kind of redundant for a game that isn't multi-threaded but will provide
|
||||
// some slight optimizations if a mod frequently creates and deletes threads.
|
||||
DisableThreadLibraryCalls(module);
|
||||
|
||||
DWORD code = loadGeode(module);
|
||||
if (code != 0)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
|
|
@ -66,46 +66,72 @@ extern "C" [[gnu::visibility("default")]] jint JNI_OnLoad(JavaVM* vm, void* rese
|
|||
#elif defined(GEODE_IS_WINDOWS)
|
||||
#include <Windows.h>
|
||||
|
||||
DWORD WINAPI loadThread(void* arg) {
|
||||
bool canMoveBootstrapper = true;
|
||||
if (auto mod = GetModuleHandleA("GeodeBootstrapper.dll")) {
|
||||
if (WaitForSingleObject(mod, 1000) != WAIT_OBJECT_0) {
|
||||
canMoveBootstrapper = false;
|
||||
}
|
||||
int WINAPI gdMainHook(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
|
||||
auto workingDir = dirs::getGameDir();
|
||||
auto updatesDir = workingDir / "geode" / "update";
|
||||
|
||||
auto error = std::error_code();
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "GeodeUpdater.exe", error) && !error) {
|
||||
ghc::filesystem::rename(updatesDir / "GeodeUpdater.exe", workingDir / "GeodeUpdater.exe", error);
|
||||
if (error)
|
||||
return error.value();
|
||||
|
||||
// launch updater
|
||||
auto updaterPath = (workingDir / "GeodeUpdater.exe").string().c_str();
|
||||
|
||||
char gdPath[MAX_PATH];
|
||||
GetModuleFileName(nullptr, gdPath, MAX_PATH);
|
||||
|
||||
// for some reason updater receives garbage as the arg if i dont copy the string like that first
|
||||
auto gdName = ghc::filesystem::path(gdPath).filename().string().c_str();
|
||||
char gdName2[MAX_PATH];
|
||||
strcpy(gdName2, gdName);
|
||||
|
||||
ShellExecute(NULL, "open", updaterPath, gdName2, workingDir.string().c_str(), FALSE);
|
||||
|
||||
// quit gd before it can even start
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (canMoveBootstrapper) {
|
||||
auto workingDir = dirs::getGameDir();
|
||||
auto updatesDir = workingDir / "geode" / "update";
|
||||
|
||||
auto error = std::error_code();
|
||||
|
||||
if (ghc::filesystem::exists(updatesDir / "GeodeBootstrapper.dll", error) && !error) {
|
||||
ghc::filesystem::rename(
|
||||
updatesDir / "GeodeBootstrapper.dll", workingDir / "GeodeBootstrapper.dll", error
|
||||
);
|
||||
if (error) return error.value();
|
||||
}
|
||||
}
|
||||
|
||||
return geodeEntry(arg);
|
||||
int exitCode = geodeEntry(hInstance);
|
||||
if (exitCode != 0)
|
||||
return exitCode;
|
||||
return reinterpret_cast<decltype(&wWinMain)>(geode::base::get() + 0x260ff8)(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE lib, DWORD reason, LPVOID) {
|
||||
switch (reason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
// Prevents threads from notifying this DLL on creation or destruction.
|
||||
// Kind of redundant for a game that isn't multi-threaded but will provide
|
||||
// some slight optimizations if a mod frequently creates and deletes threads.
|
||||
DisableThreadLibraryCalls(lib);
|
||||
extern "C" __declspec(dllexport) DWORD WINAPI loadGeode(void* arg) {
|
||||
auto process = GetCurrentProcess();
|
||||
|
||||
// loading thread
|
||||
HANDLE _ = CreateThread(0, 0, loadThread, lib, 0, nullptr);
|
||||
if (_) CloseHandle(_);
|
||||
auto patchAddr = reinterpret_cast<void*>(geode::base::get() + 0x260ff8);
|
||||
constexpr SIZE_T patchLength = 13;
|
||||
auto detourAddr = reinterpret_cast<uintptr_t>(&gdMainHook) - geode::base::get() - 0x261005;
|
||||
auto detourAddrPtr = reinterpret_cast<uint8_t*>(&detourAddr);
|
||||
|
||||
break;
|
||||
uint8_t patchBytes[patchLength] = {
|
||||
0x55,
|
||||
0x8b, 0xec,
|
||||
0x83, 0xe4, 0xf8,
|
||||
0xeb, 0x06,
|
||||
0xe9, detourAddrPtr[0], detourAddrPtr[1], detourAddrPtr[2], detourAddrPtr[3]
|
||||
};
|
||||
|
||||
DWORD oldProtect;
|
||||
BOOL res = TRUE;
|
||||
res = res && VirtualProtectEx(process, patchAddr, patchLength, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
res = res && WriteProcessMemory(process, patchAddr, patchBytes, patchLength, nullptr);
|
||||
res = res && VirtualProtectEx(process, patchAddr, patchLength, oldProtect, &oldProtect);
|
||||
|
||||
if (!res) {
|
||||
LoaderImpl::get()->platformMessageBox(
|
||||
"Unable to Load Geode!",
|
||||
"There was an unknown fatal error hooking "
|
||||
"the GD main function and Geode can not be loaded."
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue