mirror of
https://github.com/mon/ifs_layeredfs.git
synced 2026-03-21 17:34:09 -05:00
180 lines
6.0 KiB
C++
180 lines
6.0 KiB
C++
#include <stdio.h>
|
|
|
|
// because GCC's exports aren't as powerful as MSVC's pragma(comment), we need
|
|
// to name our functions identically to the real ones, which actually collides
|
|
// with the real ones if we include <windows.h>. So instead, include these
|
|
// lesser-used actual imports
|
|
#include <errhandlingapi.h>
|
|
#include <libloaderapi.h>
|
|
#include <sysinfoapi.h>
|
|
|
|
#define DLL_TO_HOOK "ifs_hook.dll"
|
|
// #define DO_LOG
|
|
|
|
// leave a bunch of room in the string so aspiring modders can just hex edit the filename
|
|
#define HELP "\0Hello hex editor - The DLL name + this message have 256 bytes allocated for them. You can change the DLL name if you want!"
|
|
const char DLL_TO_LOAD[256] = DLL_TO_HOOK HELP;
|
|
|
|
#if defined(USE_D3D9) // Anything that uses D3d9.dll, which is most games
|
|
#define DLL_NAME L"d3d9.dll"
|
|
|
|
#define FOREACH_D3D_FUNC(X) \
|
|
X(20, "", Direct3DCreate9On12) \
|
|
X(21, "", Direct3DCreate9On12Ex) \
|
|
X(24, "", Direct3DShaderValidatorCreate9) \
|
|
X(25, "", PSGPError) \
|
|
X(26, "", PSGPSampleTexture) \
|
|
X(27, "", D3DPERF_BeginEvent) \
|
|
X(28, "", D3DPERF_EndEvent) \
|
|
X(29, "", D3DPERF_GetStatus) \
|
|
X(30, "", D3DPERF_QueryRepeatFrame) \
|
|
X(31, "", D3DPERF_SetMarker) \
|
|
X(32, "", D3DPERF_SetOptions) \
|
|
X(33, "", D3DPERF_SetRegion) \
|
|
X(34, "", DebugSetLevel) \
|
|
X(35, "", DebugSetMute) \
|
|
X(36, "", Direct3D9EnableMaximizedWindowedModeShim) \
|
|
X(37, "", Direct3DCreate9) \
|
|
X(38, "", Direct3DCreate9Ex) \
|
|
|
|
#elif defined(USE_DXGI) // Anything newer will include dxgi transitively, so D3d10/11/12 are all covered
|
|
#define DLL_NAME L"dxgi.dll"
|
|
|
|
#define FOREACH_D3D_FUNC(X) \
|
|
X(1, "", ApplyCompatResolutionQuirking) \
|
|
X(2, "", CompatString) \
|
|
X(3, "", CompatValue) \
|
|
X(4, "", DXGIDumpJournal) \
|
|
X(5, "", PIXBeginCapture) \
|
|
X(6, "", PIXEndCapture) \
|
|
X(7, "", PIXGetCaptureState) \
|
|
X(8, "", SetAppCompatStringPointer) \
|
|
X(9, "", UpdateHMDEmulationStatus) \
|
|
X(10, "", CreateDXGIFactory) \
|
|
X(11, "", CreateDXGIFactory1) \
|
|
X(12, "", CreateDXGIFactory2) \
|
|
X(13, "", DXGID3D10CreateDevice) \
|
|
X(14, "", DXGID3D10CreateLayeredDevice) \
|
|
X(15, "", DXGID3D10GetLayeredDeviceSize) \
|
|
X(16, "", DXGID3D10RegisterLayers) \
|
|
X(17, "", DXGIDeclareAdapterRemovalSupport) \
|
|
X(18, "", DXGIGetDebugInterface1) \
|
|
X(19, "", DXGIReportAdapterConfiguration) \
|
|
|
|
#elif defined(USE_OGL) // OpenGL used by jubeat, older gfdm
|
|
#define DLL_NAME L"opengl32.dll"
|
|
|
|
// this one has tons of defs so put it in a separate file
|
|
#include "opengl_defs.h"
|
|
|
|
#else
|
|
#error choose a valid DLL to hook
|
|
#endif
|
|
|
|
// Notes on register preservation and safety etc
|
|
// cdecl/stdcall both push args on stack, on x64 also uses registers.
|
|
//
|
|
// On x86, with at least 1 arg in the wrapped function, the compiler
|
|
// correctly generates stack preservation code.
|
|
//
|
|
// Note! If the wrapped function is cdecl instead of stdcall, it'll
|
|
// need arg propagation. Having it be stdcall makes it a jmp.
|
|
//
|
|
// On x64, things are more complex because stdcall isn't used.
|
|
// 0-arg functions are fine, but because args are placed in registers
|
|
// (RCX, RDX, R8, R9) and only then overflowed into stack, they need anti-clobber
|
|
// code.
|
|
//
|
|
// Thus, by making the wrapped function have 4 args and stdcall, we
|
|
// generate correct register preservation for both x86 and x64 targets.
|
|
// If the function isn't stdcall or cdecl, you're out of luck, but I've
|
|
// never seen a DLL do that so it Should Totes Be Fine Yo (TM).
|
|
|
|
#define DECLARE_ORIGINAL(ordinal, noname, name) void (WINAPI *real_ ## name)(void* a, void* b, void* c, void* d);
|
|
FOREACH_D3D_FUNC(DECLARE_ORIGINAL);
|
|
|
|
#ifdef DO_LOG
|
|
FILE* logfile;
|
|
#define LOG(...) if (logfile) fprintf(logfile, __VA_ARGS__); fflush(logfile);
|
|
|
|
#else
|
|
#define LOG(...)
|
|
|
|
#endif
|
|
|
|
void __cdecl onetime_setup(const char *fn_name) {
|
|
static bool setup_complete = false;
|
|
|
|
LOG("%s\n", fn_name);
|
|
|
|
if (setup_complete)
|
|
return;
|
|
|
|
#ifdef DO_LOG
|
|
fopen_s(&logfile, "d3d_hook.log", "w");
|
|
LOG("Init via %s\n", fn_name);
|
|
#endif
|
|
|
|
#ifdef BOMBERGIRL_BULLSHIT
|
|
// it rewrites the path loader and needs "_dxgi.dll" copied out of system32
|
|
// since the loader doesn't deal with full paths properly
|
|
wchar_t path[] = L"_" DLL_NAME;
|
|
HMODULE orig = LoadLibraryW(path);
|
|
#else
|
|
wchar_t path[MAX_PATH];
|
|
if (GetSystemDirectoryW(path, sizeof(path)) == 0) {
|
|
LOG("Couldn't GetSystemDirectoryW, enjoy your crash\n");
|
|
return;
|
|
}
|
|
|
|
if (wcslen(path) + wcslen(L"\\" DLL_NAME) >= MAX_PATH) {
|
|
LOG("Original DLL path length exceeds MAX_PATH, enjoy your crash\n");
|
|
return;
|
|
}
|
|
|
|
// can't use wcscat_s, not available on XP
|
|
wcscat(path, L"\\" DLL_NAME);
|
|
HMODULE orig = LoadLibraryW(path);
|
|
#endif
|
|
|
|
if (!orig) {
|
|
LOG("Couldn't load original dll at %ls, errno %d, enjoy your crash\n", path, (int)GetLastError());
|
|
}
|
|
|
|
#define LOAD_ORIGINAL(ordinal, noname, name) \
|
|
real_ ## name = (decltype(real_ ## name))GetProcAddress( \
|
|
orig, strlen(noname) == 0 ? #name : (const char*)ordinal); \
|
|
if(!real_ ## name) \
|
|
LOG("Couldn't load " #name " , enjoy your crash\n");
|
|
|
|
FOREACH_D3D_FUNC(LOAD_ORIGINAL);
|
|
|
|
// off we go
|
|
LoadLibraryA(DLL_TO_LOAD);
|
|
setup_complete = true;
|
|
|
|
LOG("Hook init done\n");
|
|
}
|
|
|
|
#define REPLICATE_FUNC(ordinal, noname, name) \
|
|
extern "C" void __stdcall name(void* a, void* b, void* c, void* d) { \
|
|
/* Using this avoids name mangling for stdcall functions (which happens even with extern "C"!) */ \
|
|
/* It also removes the need for a .def file */ \
|
|
/* ...but only for MSVC. GCC's asm(".section .drectve") and -export directive does not work on ordinals, nor on mangled names */ \
|
|
/*__pragma(comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__ ",@" #ordinal noname))*/ \
|
|
onetime_setup(__FUNCTION__); \
|
|
return real_ ## name(a,b,c,d); \
|
|
}
|
|
|
|
FOREACH_D3D_FUNC(REPLICATE_FUNC);
|
|
|
|
BOOL APIENTRY DllMain( HMODULE hModule,
|
|
DWORD ul_reason_for_call,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) const char __layeredfs_version[] = VER_STRING;
|