Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
d1442e3747
1382 changed files with 170725 additions and 0 deletions
45
Native/InjectModern/CMakeLists.txt
Normal file
45
Native/InjectModern/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
project(Inject LANGUAGES CXX)
|
||||
|
||||
# Force x86 (32-bit) build
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
message(WARNING "Inject.DLL must be built as x86 (32-bit). Use -A Win32 with Visual Studio generator.")
|
||||
endif()
|
||||
|
||||
add_library(Inject SHARED
|
||||
Inject.cpp
|
||||
Inject.h
|
||||
Inject.def
|
||||
)
|
||||
|
||||
target_compile_definitions(Inject PRIVATE
|
||||
WIN32
|
||||
_WINDOWS
|
||||
INJECT_EXPORTS
|
||||
_USRDLL
|
||||
UNICODE
|
||||
_UNICODE
|
||||
)
|
||||
|
||||
target_link_libraries(Inject PRIVATE
|
||||
d3d9
|
||||
advapi32
|
||||
user32
|
||||
kernel32
|
||||
ole32
|
||||
oleaut32
|
||||
)
|
||||
|
||||
# MSVC-specific settings
|
||||
if(MSVC)
|
||||
target_compile_options(Inject PRIVATE /W3 /GR- /EHsc)
|
||||
set_target_properties(Inject PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(Inject PROPERTIES
|
||||
OUTPUT_NAME "Inject"
|
||||
SUFFIX ".DLL"
|
||||
)
|
||||
495
Native/InjectModern/Inject.cpp
Normal file
495
Native/InjectModern/Inject.cpp
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
// Inject.cpp - Modern D3D9 implementation of Inject.DLL for Decal
|
||||
//
|
||||
// This DLL gets injected into the Asheron's Call game client process.
|
||||
// It hooks the D3D9 rendering pipeline to enable Decal's overlay system,
|
||||
// manages the plugin lifecycle, and provides vtable hooking utilities.
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define INJECT_EXPORTS
|
||||
#include <windows.h>
|
||||
#include <d3d9.h>
|
||||
#include <tchar.h>
|
||||
#include <string>
|
||||
|
||||
#include "Inject.h"
|
||||
|
||||
#pragma comment(lib, "d3d9.lib")
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared data section - accessible across processes using this DLL
|
||||
// ---------------------------------------------------------------------------
|
||||
#pragma data_seg(".InjectDll")
|
||||
static HHOOK g_hHook = NULL;
|
||||
#pragma data_seg()
|
||||
#pragma comment(linker, "/SECTION:.InjectDll,RWS")
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Globals
|
||||
// ---------------------------------------------------------------------------
|
||||
static HINSTANCE g_hInstance = NULL;
|
||||
static HWND g_hGameWindow = NULL;
|
||||
static IDirect3DDevice9* g_pDevice = NULL;
|
||||
static WNDPROC g_pfnOrigWndProc = NULL;
|
||||
static bool g_bInitialized = false;
|
||||
static bool g_bContainerMode = false;
|
||||
|
||||
// COM interface pointers for managed Decal core
|
||||
typedef HRESULT(__stdcall* PFN_CO_CREATE)(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*);
|
||||
static IUnknown* g_pDecalCore = NULL;
|
||||
|
||||
// Original D3D9 method pointers (saved before hooking)
|
||||
extern "C" INJECT_API void* BeginSceneO = NULL;
|
||||
extern "C" INJECT_API void* EndSceneO = NULL;
|
||||
|
||||
// Saved vtable entries for unhooking
|
||||
struct VTablePatch
|
||||
{
|
||||
void* pInterface;
|
||||
int nIndex;
|
||||
void* pOriginal;
|
||||
};
|
||||
static VTablePatch g_patches[64];
|
||||
static int g_nPatchCount = 0;
|
||||
|
||||
// Registry path constants
|
||||
static const TCHAR* REG_DECAL_KEY = _T("SOFTWARE\\Decal");
|
||||
static const TCHAR* REG_AGENT_KEY = _T("SOFTWARE\\Decal\\Agent");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Path mapping
|
||||
// ---------------------------------------------------------------------------
|
||||
static std::basic_string<TCHAR> GetAgentPath()
|
||||
{
|
||||
HKEY hKey;
|
||||
TCHAR szPath[MAX_PATH] = {};
|
||||
DWORD dwSize = MAX_PATH * sizeof(TCHAR);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_AGENT_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, _T("AgentPath"), NULL, NULL, (LPBYTE)szPath, &dwSize);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return szPath;
|
||||
}
|
||||
|
||||
extern "C" INJECT_API LPTSTR __stdcall InjectMapPath(int pathType, LPCTSTR szFilename, LPTSTR szBuffer)
|
||||
{
|
||||
std::basic_string<TCHAR> base;
|
||||
|
||||
if (pathType == 0) // eInjectPathDatFile - AC installation directory
|
||||
{
|
||||
HKEY hKey;
|
||||
TCHAR szPath[MAX_PATH] = {};
|
||||
DWORD dwSize = MAX_PATH * sizeof(TCHAR);
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00"),
|
||||
0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegQueryValueEx(hKey, _T("GamePath"), NULL, NULL, (LPBYTE)szPath, &dwSize);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
base = szPath;
|
||||
}
|
||||
else // eInjectPathAgent - Decal agent directory
|
||||
{
|
||||
base = GetAgentPath();
|
||||
}
|
||||
|
||||
// Ensure trailing backslash
|
||||
if (!base.empty() && base.back() != _T('\\'))
|
||||
base += _T('\\');
|
||||
|
||||
_tcscpy(szBuffer, (base + szFilename).c_str());
|
||||
return szBuffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// VTable hooking utilities
|
||||
// ---------------------------------------------------------------------------
|
||||
extern "C" INJECT_API void* __stdcall GetVTableEntry(void* pInterface, int nIndex)
|
||||
{
|
||||
if (!pInterface)
|
||||
return NULL;
|
||||
|
||||
// COM interface vtable: first DWORD at *pInterface is pointer to vtable array
|
||||
void** vtable = *(void***)pInterface;
|
||||
return vtable[nIndex];
|
||||
}
|
||||
|
||||
extern "C" INJECT_API BOOL __stdcall HookVTable(void* pInterface, int nIndex, void* pNewFunction)
|
||||
{
|
||||
if (!pInterface || !pNewFunction)
|
||||
return FALSE;
|
||||
|
||||
void** vtable = *(void***)pInterface;
|
||||
void* pOriginal = vtable[nIndex];
|
||||
|
||||
// Change page protection to allow write
|
||||
DWORD dwOldProtect;
|
||||
if (!VirtualProtect(&vtable[nIndex], sizeof(void*), PAGE_READWRITE, &dwOldProtect))
|
||||
return FALSE;
|
||||
|
||||
// Patch the vtable entry
|
||||
vtable[nIndex] = pNewFunction;
|
||||
|
||||
// Restore protection
|
||||
VirtualProtect(&vtable[nIndex], sizeof(void*), dwOldProtect, &dwOldProtect);
|
||||
|
||||
// Save for unhooking
|
||||
if (g_nPatchCount < _countof(g_patches))
|
||||
{
|
||||
g_patches[g_nPatchCount].pInterface = pInterface;
|
||||
g_patches[g_nPatchCount].nIndex = nIndex;
|
||||
g_patches[g_nPatchCount].pOriginal = pOriginal;
|
||||
g_nPatchCount++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" INJECT_API BOOL __stdcall UnhookVTable(void* pInterface, int nIndex)
|
||||
{
|
||||
// Find the saved original and restore it
|
||||
for (int i = 0; i < g_nPatchCount; i++)
|
||||
{
|
||||
if (g_patches[i].pInterface == pInterface && g_patches[i].nIndex == nIndex)
|
||||
{
|
||||
void** vtable = *(void***)pInterface;
|
||||
|
||||
DWORD dwOldProtect;
|
||||
if (!VirtualProtect(&vtable[nIndex], sizeof(void*), PAGE_READWRITE, &dwOldProtect))
|
||||
return FALSE;
|
||||
|
||||
vtable[nIndex] = g_patches[i].pOriginal;
|
||||
VirtualProtect(&vtable[nIndex], sizeof(void*), dwOldProtect, &dwOldProtect);
|
||||
|
||||
// Remove from patch list
|
||||
g_patches[i] = g_patches[g_nPatchCount - 1];
|
||||
g_nPatchCount--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Memory patching
|
||||
// ---------------------------------------------------------------------------
|
||||
extern "C" INJECT_API BOOL __stdcall PatchMemory(void* pAddress, const void* pData, DWORD dwSize)
|
||||
{
|
||||
DWORD dwOldProtect;
|
||||
if (!VirtualProtect(pAddress, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect))
|
||||
return FALSE;
|
||||
|
||||
memcpy(pAddress, pData, dwSize);
|
||||
|
||||
VirtualProtect(pAddress, dwSize, dwOldProtect, &dwOldProtect);
|
||||
FlushInstructionCache(GetCurrentProcess(), pAddress, dwSize);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// D3D9 hook trampolines
|
||||
// ---------------------------------------------------------------------------
|
||||
typedef HRESULT(__stdcall* PFN_BeginScene)(IDirect3DDevice9*);
|
||||
typedef HRESULT(__stdcall* PFN_EndScene)(IDirect3DDevice9*);
|
||||
typedef HRESULT(__stdcall* PFN_Reset)(IDirect3DDevice9*, D3DPRESENT_PARAMETERS*);
|
||||
|
||||
static PFN_Reset g_pfnOrigReset = NULL;
|
||||
|
||||
// Forward declarations for managed-layer callbacks
|
||||
typedef void(__stdcall* PFN_DecalCallback)();
|
||||
static PFN_DecalCallback g_pfnRender3D = NULL;
|
||||
static PFN_DecalCallback g_pfnRender2D = NULL;
|
||||
static PFN_DecalCallback g_pfnPreReset = NULL;
|
||||
static PFN_DecalCallback g_pfnPostReset = NULL;
|
||||
|
||||
// Hooked BeginScene - called every frame before rendering
|
||||
static HRESULT __stdcall Hooked_BeginScene(IDirect3DDevice9* pDevice)
|
||||
{
|
||||
PFN_BeginScene pfnOrig = (PFN_BeginScene)BeginSceneO;
|
||||
HRESULT hr = pfnOrig(pDevice);
|
||||
|
||||
// Store device reference on first call
|
||||
if (!g_pDevice)
|
||||
{
|
||||
g_pDevice = pDevice;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Hooked EndScene - called every frame after rendering; we draw our overlay here
|
||||
static HRESULT __stdcall Hooked_EndScene(IDirect3DDevice9* pDevice)
|
||||
{
|
||||
// Render 3D overlays (D3DService markers) before EndScene
|
||||
if (g_pfnRender3D)
|
||||
g_pfnRender3D();
|
||||
|
||||
// Render 2D overlays (HUDs, UI) before EndScene
|
||||
if (g_pfnRender2D)
|
||||
g_pfnRender2D();
|
||||
|
||||
PFN_EndScene pfnOrig = (PFN_EndScene)EndSceneO;
|
||||
return pfnOrig(pDevice);
|
||||
}
|
||||
|
||||
// Hooked Reset - device lost/restore cycle
|
||||
static HRESULT __stdcall Hooked_Reset(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS* pParams)
|
||||
{
|
||||
// Notify managed layer to release D3D resources
|
||||
if (g_pfnPreReset)
|
||||
g_pfnPreReset();
|
||||
|
||||
HRESULT hr = g_pfnOrigReset(pDevice, pParams);
|
||||
|
||||
// Notify managed layer to recreate D3D resources
|
||||
if (g_pfnPostReset)
|
||||
g_pfnPostReset();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// D3D9 device discovery and hooking
|
||||
// ---------------------------------------------------------------------------
|
||||
static bool HookD3D9Device()
|
||||
{
|
||||
// Create a temporary D3D9 device to get its vtable
|
||||
IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
if (!pD3D)
|
||||
return false;
|
||||
|
||||
D3DPRESENT_PARAMETERS pp = {};
|
||||
pp.Windowed = TRUE;
|
||||
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
pp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
pp.hDeviceWindow = g_hGameWindow;
|
||||
|
||||
IDirect3DDevice9* pTempDevice = NULL;
|
||||
HRESULT hr = pD3D->CreateDevice(
|
||||
D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, g_hGameWindow,
|
||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
|
||||
&pp, &pTempDevice);
|
||||
|
||||
if (FAILED(hr) || !pTempDevice)
|
||||
{
|
||||
pD3D->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get vtable pointers from the temporary device
|
||||
void** vtable = *(void***)pTempDevice;
|
||||
|
||||
// IDirect3DDevice9 vtable indices:
|
||||
// [41] = BeginScene
|
||||
// [42] = EndScene
|
||||
// [16] = Reset
|
||||
BeginSceneO = vtable[41];
|
||||
EndSceneO = vtable[42];
|
||||
g_pfnOrigReset = (PFN_Reset)vtable[16];
|
||||
|
||||
pTempDevice->Release();
|
||||
pD3D->Release();
|
||||
|
||||
// Now hook the actual game's D3D9 device vtable
|
||||
// We patch the device class vtable (shared by all D3D9 devices of the same type)
|
||||
// The temp device gave us the vtable layout; actual hooking happens via HookVTable
|
||||
// when the real device is discovered.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Window subclass procedure
|
||||
// ---------------------------------------------------------------------------
|
||||
static LRESULT CALLBACK InjectWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (uMsg == WM_DESTROY)
|
||||
{
|
||||
// Game is shutting down - clean up
|
||||
Container_StopPlugins();
|
||||
Container_Terminate();
|
||||
}
|
||||
|
||||
return CallWindowProc(g_pfnOrigWndProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Startup / lifecycle
|
||||
// ---------------------------------------------------------------------------
|
||||
extern "C" INJECT_API void __stdcall DecalStartup()
|
||||
{
|
||||
if (g_bInitialized)
|
||||
return;
|
||||
|
||||
// Find the game window
|
||||
g_hGameWindow = FindWindow(NULL, _T("Asheron's Call"));
|
||||
if (!g_hGameWindow)
|
||||
return;
|
||||
|
||||
// Subclass the game window to intercept messages
|
||||
g_pfnOrigWndProc = (WNDPROC)SetWindowLongPtr(g_hGameWindow, GWLP_WNDPROC, (LONG_PTR)InjectWndProc);
|
||||
|
||||
// Initialize COM
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
// Discover D3D9 vtable layout for hooking
|
||||
HookD3D9Device();
|
||||
|
||||
// Create the managed Decal core (Decal.Core COM server)
|
||||
// CLSID_DecalCore = {4557D5A1-...}
|
||||
CLSID clsidDecal;
|
||||
CLSIDFromProgID(L"Decal.Core", &clsidDecal);
|
||||
|
||||
HRESULT hr = CoCreateInstance(clsidDecal, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IUnknown, (void**)&g_pDecalCore);
|
||||
|
||||
if (SUCCEEDED(hr) && g_pDecalCore)
|
||||
{
|
||||
// The managed Decal.Core will enumerate and start services/plugins
|
||||
// via registry entries under HKLM\SOFTWARE\Decal\Services and \Plugins
|
||||
}
|
||||
|
||||
g_bInitialized = true;
|
||||
}
|
||||
|
||||
extern "C" INJECT_API void __stdcall Container_Initialize(HWND hWnd, void* pDevice)
|
||||
{
|
||||
g_hGameWindow = hWnd;
|
||||
g_pDevice = (IDirect3DDevice9*)pDevice;
|
||||
g_bContainerMode = true;
|
||||
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
CLSID clsidDecal;
|
||||
CLSIDFromProgID(L"Decal.Core", &clsidDecal);
|
||||
CoCreateInstance(clsidDecal, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IUnknown, (void**)&g_pDecalCore);
|
||||
}
|
||||
|
||||
extern "C" INJECT_API void __stdcall Container_StartPlugins()
|
||||
{
|
||||
// Delegate to managed layer
|
||||
// The managed Decal.Core handles plugin enumeration and loading
|
||||
}
|
||||
|
||||
extern "C" INJECT_API void __stdcall Container_StopPlugins()
|
||||
{
|
||||
// Delegate to managed layer
|
||||
}
|
||||
|
||||
extern "C" INJECT_API void __stdcall Container_Terminate()
|
||||
{
|
||||
if (g_pDecalCore)
|
||||
{
|
||||
g_pDecalCore->Release();
|
||||
g_pDecalCore = NULL;
|
||||
}
|
||||
|
||||
// Restore window procedure
|
||||
if (g_hGameWindow && g_pfnOrigWndProc)
|
||||
{
|
||||
SetWindowLongPtr(g_hGameWindow, GWLP_WNDPROC, (LONG_PTR)g_pfnOrigWndProc);
|
||||
g_pfnOrigWndProc = NULL;
|
||||
}
|
||||
|
||||
// Unhook all vtable patches
|
||||
while (g_nPatchCount > 0)
|
||||
{
|
||||
int i = g_nPatchCount - 1;
|
||||
void** vtable = *(void***)g_patches[i].pInterface;
|
||||
|
||||
DWORD dwOldProtect;
|
||||
VirtualProtect(&vtable[g_patches[i].nIndex], sizeof(void*), PAGE_READWRITE, &dwOldProtect);
|
||||
vtable[g_patches[i].nIndex] = g_patches[i].pOriginal;
|
||||
VirtualProtect(&vtable[g_patches[i].nIndex], sizeof(void*), dwOldProtect, &dwOldProtect);
|
||||
|
||||
g_nPatchCount--;
|
||||
}
|
||||
|
||||
g_pDevice = NULL;
|
||||
g_bInitialized = false;
|
||||
}
|
||||
|
||||
extern "C" INJECT_API void __stdcall Container_Draw()
|
||||
{
|
||||
if (g_pfnRender2D)
|
||||
g_pfnRender2D();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// COM server stubs (ATL-free, minimal)
|
||||
// ---------------------------------------------------------------------------
|
||||
static LONG g_lLockCount = 0;
|
||||
|
||||
STDAPI DllCanUnloadNow()
|
||||
{
|
||||
return (g_lLockCount == 0 && !g_bInitialized) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
||||
{
|
||||
*ppv = NULL;
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
STDAPI DllRegisterServer()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// DllMain
|
||||
// ---------------------------------------------------------------------------
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_hInstance = hInstance;
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
|
||||
// Check if we're in the AC client process
|
||||
{
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
GetModuleFileName(NULL, szFilename, MAX_PATH);
|
||||
|
||||
// Extract just the filename
|
||||
LPTSTR pName = _tcsrchr(szFilename, _T('\\'));
|
||||
if (pName)
|
||||
pName++;
|
||||
else
|
||||
pName = szFilename;
|
||||
|
||||
// If running inside client.exe, auto-start Decal
|
||||
if (_tcsnicmp(pName, _T("client"), 6) == 0 ||
|
||||
_tcsnicmp(pName, _T("acclient"), 8) == 0)
|
||||
{
|
||||
// Increment our own ref count to prevent premature unloading
|
||||
TCHAR szModule[MAX_PATH];
|
||||
GetModuleFileName(hInstance, szModule, MAX_PATH);
|
||||
LoadLibrary(szModule);
|
||||
|
||||
// Start Decal hooking
|
||||
DecalStartup();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
Container_Terminate();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
37
Native/InjectModern/Inject.def
Normal file
37
Native/InjectModern/Inject.def
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
; Inject.def - Module definition for Inject.DLL
|
||||
; Matches the exports of the original v2.9.8.3 Inject.DLL
|
||||
|
||||
LIBRARY "Inject"
|
||||
|
||||
SECTIONS
|
||||
.InjectDll READ WRITE SHARED
|
||||
|
||||
EXPORTS
|
||||
; COM server
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
|
||||
; D3D9 original function pointers (data exports)
|
||||
BeginSceneO DATA
|
||||
EndSceneO DATA
|
||||
|
||||
; Lifecycle
|
||||
DecalStartup
|
||||
Container_Initialize
|
||||
Container_StartPlugins
|
||||
Container_StopPlugins
|
||||
Container_Terminate
|
||||
Container_Draw
|
||||
|
||||
; VTable hooking utilities
|
||||
HookVTable
|
||||
UnhookVTable
|
||||
GetVTableEntry
|
||||
|
||||
; Memory patching
|
||||
PatchMemory
|
||||
|
||||
; Path mapping
|
||||
InjectMapPath
|
||||
37
Native/InjectModern/Inject.h
Normal file
37
Native/InjectModern/Inject.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Inject.h - Public declarations for Inject.DLL
|
||||
#pragma once
|
||||
|
||||
#ifdef INJECT_EXPORTS
|
||||
#define INJECT_API __declspec(dllexport)
|
||||
#else
|
||||
#define INJECT_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
// Lifecycle exports
|
||||
extern "C" INJECT_API void __stdcall DecalStartup();
|
||||
extern "C" INJECT_API void __stdcall Container_Initialize(HWND hWnd, void* pDevice);
|
||||
extern "C" INJECT_API void __stdcall Container_StartPlugins();
|
||||
extern "C" INJECT_API void __stdcall Container_StopPlugins();
|
||||
extern "C" INJECT_API void __stdcall Container_Terminate();
|
||||
extern "C" INJECT_API void __stdcall Container_Draw();
|
||||
|
||||
// D3D9 vtable hooking utilities
|
||||
extern "C" INJECT_API BOOL __stdcall HookVTable(void* pInterface, int nIndex, void* pNewFunction);
|
||||
extern "C" INJECT_API BOOL __stdcall UnhookVTable(void* pInterface, int nIndex);
|
||||
extern "C" INJECT_API void* __stdcall GetVTableEntry(void* pInterface, int nIndex);
|
||||
|
||||
// Memory patching
|
||||
extern "C" INJECT_API BOOL __stdcall PatchMemory(void* pAddress, const void* pData, DWORD dwSize);
|
||||
|
||||
// Original D3D9 function pointers (for DecalRender/D3DService to call through)
|
||||
extern "C" INJECT_API void* BeginSceneO;
|
||||
extern "C" INJECT_API void* EndSceneO;
|
||||
|
||||
// Path mapping
|
||||
extern "C" INJECT_API LPTSTR __stdcall InjectMapPath(int pathType, LPCTSTR szFilename, LPTSTR szBuffer);
|
||||
|
||||
// COM server standard exports
|
||||
STDAPI DllCanUnloadNow();
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
|
||||
STDAPI DllRegisterServer();
|
||||
STDAPI DllUnregisterServer();
|
||||
Loading…
Add table
Add a link
Reference in a new issue