2024-06-02 16:46:01 -04:00
|
|
|
#include <Windows.h>
|
|
|
|
#include <string>
|
2024-06-24 15:25:15 -04:00
|
|
|
#include <array>
|
|
|
|
#include <vector>
|
|
|
|
#include <filesystem>
|
2024-06-02 16:46:01 -04:00
|
|
|
|
2024-06-03 12:36:51 -04:00
|
|
|
struct XINPUT_STATE;
|
|
|
|
struct XINPUT_CAPABILITIES;
|
2024-06-02 16:46:01 -04:00
|
|
|
|
2024-06-03 12:36:51 -04:00
|
|
|
constexpr static auto MAX_PATH_CHARS = 32768u;
|
2024-06-02 16:46:01 -04:00
|
|
|
|
2024-06-03 12:36:51 -04:00
|
|
|
static HMODULE getXInput() {
|
|
|
|
static auto xinput = []() -> HMODULE {
|
|
|
|
std::wstring path(MAX_PATH_CHARS, L'\0');
|
2024-09-12 12:02:30 -04:00
|
|
|
auto size = GetSystemDirectoryW(path.data(), path.size());
|
2024-06-03 12:36:51 -04:00
|
|
|
if (size) {
|
|
|
|
path.resize(size);
|
|
|
|
return LoadLibraryW((path + L"\\XInput1_4.dll").c_str());
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}();
|
2024-06-02 16:46:01 -04:00
|
|
|
|
2024-06-03 12:36:51 -04:00
|
|
|
return xinput;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FARPROC getFP(const std::string& sym) {
|
|
|
|
if (auto xinput = getXInput())
|
|
|
|
return GetProcAddress(xinput, sym.c_str());
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2024-06-02 16:46:01 -04:00
|
|
|
|
|
|
|
#pragma comment(linker, "/export:XInputGetState,@2")
|
|
|
|
extern "C" DWORD XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState) {
|
2024-06-03 12:36:51 -04:00
|
|
|
static auto fp = getFP("XInputGetState");
|
|
|
|
if (fp) {
|
|
|
|
using FPType = decltype(&XInputGetState);
|
|
|
|
return reinterpret_cast<FPType>(fp)(dwUserIndex, pState);
|
2024-06-02 16:46:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_DEVICE_NOT_CONNECTED;
|
|
|
|
}
|
|
|
|
|
2024-06-03 10:03:37 -04:00
|
|
|
#pragma comment(linker, "/export:XInputGetCapabilities,@4")
|
|
|
|
extern "C" DWORD XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities) {
|
2024-06-03 12:36:51 -04:00
|
|
|
static auto fp = getFP("XInputGetCapabilities");
|
|
|
|
if (fp) {
|
|
|
|
using FPType = decltype(&XInputGetCapabilities);
|
|
|
|
return reinterpret_cast<FPType>(fp)(dwUserIndex, dwFlags, pCapabilities);
|
2024-06-03 10:03:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_DEVICE_NOT_CONNECTED;
|
|
|
|
}
|
|
|
|
|
2024-06-10 14:36:00 -04:00
|
|
|
static std::wstring getErrorString(DWORD error) {
|
|
|
|
return L"Could not load Geode! Error code: " + std::to_wstring(error);
|
|
|
|
}
|
|
|
|
|
2024-06-11 09:04:15 -04:00
|
|
|
static DWORD errorThread(LPVOID param) {
|
|
|
|
constexpr wchar_t REDIST_ERROR[] = L"Could not load Geode!\n"
|
|
|
|
"This is likely due to an outdated redist package.\n"
|
|
|
|
"Do you want to update Microsoft Visual C++ Redistributable 2022 to try to fix this issue?";
|
2024-06-24 15:25:15 -04:00
|
|
|
constexpr wchar_t ALT_REDIST_ERROR[] = L"Could not load Geode!\n\n"
|
|
|
|
"Please **delete** the following files from your Geometry Dash directory and try again: ";
|
2024-06-11 09:04:15 -04:00
|
|
|
const DWORD error = reinterpret_cast<DWORD64>(param);
|
|
|
|
|
|
|
|
if (error == ERROR_DLL_INIT_FAILED) {
|
2024-06-24 15:25:15 -04:00
|
|
|
|
|
|
|
std::array<std::wstring, 4> msvcpDlls = {
|
|
|
|
L"msvcp140.dll",
|
|
|
|
L"msvcp140d.dll",
|
|
|
|
L"vcruntime140.dll",
|
|
|
|
L"vcruntime140d.dll"
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<std::wstring> foundDlls;
|
|
|
|
for(auto dll : msvcpDlls) {
|
|
|
|
if(std::filesystem::exists(dll)) {
|
|
|
|
foundDlls.push_back(dll);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(foundDlls.empty()) {
|
|
|
|
const auto choice = MessageBoxW(NULL, REDIST_ERROR, L"Load failed", MB_YESNO | MB_ICONWARNING);
|
2024-06-11 09:04:15 -04:00
|
|
|
if (choice == IDYES)
|
|
|
|
ShellExecuteW(NULL, L"open", L"https://aka.ms/vs/17/release/vc_redist.x64.exe", NULL, NULL, SW_SHOWNORMAL);
|
2024-06-24 15:25:15 -04:00
|
|
|
} else {
|
|
|
|
std::wstring files = ALT_REDIST_ERROR;
|
|
|
|
bool first = true;
|
|
|
|
for(auto dll : foundDlls) {
|
|
|
|
if(!first) files += L", ";
|
|
|
|
files += dll;
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
const auto choice = MessageBoxW(NULL, files.c_str(), L"Load failed", MB_OK | MB_ICONWARNING);
|
|
|
|
}
|
|
|
|
|
2024-06-11 09:04:15 -04:00
|
|
|
} else {
|
|
|
|
MessageBoxW(NULL, getErrorString(error).c_str(), L"Load failed" , MB_OK | MB_ICONWARNING);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0u;
|
2024-06-02 16:46:01 -04:00
|
|
|
}
|
|
|
|
|
2024-06-03 12:36:51 -04:00
|
|
|
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID _) {
|
2024-06-02 16:46:01 -04:00
|
|
|
if (reason == DLL_PROCESS_ATTACH) {
|
|
|
|
DisableThreadLibraryCalls(module);
|
|
|
|
|
|
|
|
// This is UB.
|
2024-06-10 14:36:00 -04:00
|
|
|
if (LoadLibraryW(L"Geode.dll") == NULL) {
|
2024-06-11 09:04:15 -04:00
|
|
|
const auto param = reinterpret_cast<LPVOID>(static_cast<DWORD64>(GetLastError()));
|
|
|
|
CreateThread(NULL, 0, &errorThread, param, 0, NULL);
|
2024-06-10 14:36:00 -04:00
|
|
|
}
|
2024-06-02 16:46:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|