micetools/src/micetools/dll/hooks/gui.c

363 lines
13 KiB
C

#include "gui.h"
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND mainWindow;
static unsigned int hookType;
static HWND window;
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
DWORD wndProcId;
GetWindowThreadProcessId(handle, &wndProcId);
if (GetCurrentProcessId() != wndProcId) return TRUE;
window = handle;
return FALSE;
}
HWND GetProcessWindow() {
window = NULL;
EnumWindows(EnumWindowsCallback, 0);
return window;
}
BOOL UnFrameWindow(HWND hwnd) {
SetLastError(ERROR_SUCCESS);
LONG style = GetWindowLongW(hwnd, GWL_STYLE);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
RECT rect;
if (!GetClientRect(hwnd, &rect)) return FALSE;
style &= ~(WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU);
if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE;
SetWindowLongW(hwnd, GWL_STYLE, style);
if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE))
return FALSE;
return TRUE;
}
BOOL FrameWindow(HWND hwnd) {
SetLastError(ERROR_SUCCESS);
LONG style = GetWindowLongW(hwnd, GWL_STYLE);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
RECT rect;
if (!GetClientRect(hwnd, &rect)) return FALSE;
style |= WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
if (!AdjustWindowRect(&rect, style, FALSE)) return FALSE;
SetWindowLongW(hwnd, GWL_STYLE, style);
if (!SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_FRAMECHANGED | SWP_NOMOVE))
return FALSE;
return TRUE;
}
BOOL GetD3D9Device(void** pTable, size_t Size) {
if (!pTable) return false;
IDirect3D9* pD3D =
(TrueDirect3DCreate9 ? TrueDirect3DCreate9 : Direct3DCreate9)(D3D_SDK_VERSION);
if (!pD3D) return false;
IDirect3DDevice9* pDummyDevice = NULL;
D3DPRESENT_PARAMETERS d3dpp = { 0 };
d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = GetProcessWindow();
HRESULT dummyDeviceCreated =
pD3D->lpVtbl->CreateDevice(pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK) {
d3dpp.Windowed = !d3dpp.Windowed;
dummyDeviceCreated = pD3D->lpVtbl->CreateDevice(
pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK) {
pD3D->lpVtbl->Release(pD3D);
return false;
}
}
memcpy(pTable, *(void***)pDummyDevice, Size);
pDummyDevice->lpVtbl->Release(pDummyDevice);
pD3D->lpVtbl->Release(pD3D);
return true;
}
static HRESULT(WINAPI* TrueEndScene)(IDirect3DDevice9*);
void draw_rect(IDirect3DDevice9* dev, int x, int y, int w, int h, unsigned char r, unsigned char g,
unsigned char b) {
D3DCOLOR rectColor = D3DCOLOR_XRGB(r, g, b);
D3DRECT BarRect = { x, y, x + w, y + h };
dev->lpVtbl->Clear(dev, 1, &BarRect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, rectColor, 0, 0);
}
HRESULT __stdcall hkEndScene(IDirect3DDevice9* pDevice) {
static bool showMenu = false;
hookType = UI_HOOK_DX9;
end_scene_hook_t* head = end_scene_hook_list;
while (head != NULL) {
head->hook(hookType, pDevice);
head = head->next;
}
return TrueEndScene(pDevice);
}
void register_gui_hook(FnEndScene* end_scene) {
end_scene_hook_t** head = &end_scene_hook_list;
while (*head != NULL) {
head = &((*head)->next);
}
end_scene_hook_t* hook = malloc(sizeof(end_scene_hook_t));
hook->hook = end_scene;
hook->next = NULL;
*head = hook;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass,
DWORD_PTR dwRefData) {
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
void post_win_create(HWND hWnd) {
// Don't double-hook!
if (TrueEndScene != NULL) return;
mainWindow = hWnd;
if (hookType == UI_HOOK_DX9) {
void* d3d9Device[119];
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) {
*((PVOID*)&TrueEndScene) = CreateHook32((PVOID)d3d9Device[42], (PVOID)hkEndScene);
}
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (int)&WndProc, (DWORD_PTR)NULL)) {
log_error("gui", "failed to SetWindowSubclass(%d)", GetLastError());
}
}
}
RECT monitorRect = { 0 };
int monitorIndex = 0;
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor,
LPARAM dwData) {
if (monitorIndex == MiceConfig.window.adaptor)
memcpy(&monitorRect, lprcMonitor, sizeof monitorRect);
monitorIndex++;
return TRUE;
}
void SetupWindowPosition(LPRECT lpRect, DWORD dwStyle) {
int x = lpRect->left;
int y = lpRect->top;
int w = lpRect->right - x;
int h = lpRect->bottom - y;
monitorIndex = 0;
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)NULL);
if (!MiceConfig.window.nosize) {
if (MiceConfig.window.w) w = MiceConfig.window.w;
if (MiceConfig.window.h) h = MiceConfig.window.h;
}
if (MiceConfig.window.centre) {
x = ((monitorRect.right - monitorRect.left) - w) / 2;
y = ((monitorRect.bottom - monitorRect.top) - h) / 2;
} else {
x = MiceConfig.window.x;
y = MiceConfig.window.y;
}
x += monitorRect.left;
y += monitorRect.top;
lpRect->left = x;
lpRect->right = x + w;
lpRect->top = y;
lpRect->bottom = y + h;
AdjustWindowRect(lpRect, dwStyle, FALSE);
}
HWND WINAPI FakeCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName,
DWORD dwStyle, int X, int Y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) {
// Pass-through for system stuff
if (lpWindowName == NULL || strcmp(lpWindowName, "OleMainThreadWndName") == 0 ||
strcmp(lpWindowName, "CicMarshalWnd") == 0) {
return TrueCreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth,
nHeight, hWndParent, hMenu, hInstance, lpParam);
}
RECT winRect;
winRect.left = X;
winRect.right = X + nWidth;
winRect.top = Y;
winRect.bottom = Y + nHeight;
SetupWindowPosition(&winRect, dwStyle);
HWND hWnd =
TrueCreateWindowExA(dwExStyle, lpClassName, "Micetools", dwStyle, winRect.left, winRect.top,
winRect.right - winRect.left, winRect.bottom - winRect.top, hWndParent,
hMenu, hInstance, lpParam);
post_win_create(hWnd);
return hWnd;
}
HWND WINAPI FakeCreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName,
DWORD dwStyle, int X, int Y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) {
// Pass-through for system stuff
if (lpWindowName == NULL || wcscmp(lpWindowName, L"OleMainThreadWndName") == 0 ||
wcscmp(lpWindowName, L"CicMarshalWnd") == 0) {
return TrueCreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth,
nHeight, hWndParent, hMenu, hInstance, lpParam);
}
RECT winRect;
winRect.left = X;
winRect.right = X + nWidth;
winRect.top = Y;
winRect.bottom = Y + nHeight;
SetupWindowPosition(&winRect, dwStyle);
HWND hWnd =
TrueCreateWindowExW(dwExStyle, lpClassName, L"Micetools", dwStyle, winRect.left,
winRect.top, winRect.right - winRect.left, winRect.bottom - winRect.top,
hWndParent, hMenu, hInstance, lpParam);
post_win_create(hWnd);
return hWnd;
}
static HRESULT(STDMETHODCALLTYPE* TrueCreateDevice)(IDirect3D9* this, UINT Adapter,
D3DDEVTYPE DeviceType, HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface);
extern RECT monitorRect;
HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDEVTYPE DeviceType,
HWND hFocusWindow, DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface) {
if (MiceConfig.window.windowed) {
pPresentationParameters->Windowed = TRUE;
pPresentationParameters->FullScreen_RefreshRateInHz = 0;
} else if (pPresentationParameters->Windowed) {
D3DDISPLAYMODE d3ddm;
this->lpVtbl->GetAdapterDisplayMode(this, Adapter, &d3ddm);
pPresentationParameters->Windowed = FALSE;
pPresentationParameters->FullScreen_RefreshRateInHz = d3ddm.RefreshRate;
}
if (MiceConfig.window.borderless)
UnFrameWindow(hFocusWindow);
else
FrameWindow(hFocusWindow);
Adapter = MiceConfig.window.adaptor;
RECT winRect;
GetWindowRect(hFocusWindow, &winRect);
DWORD dwStyle = GetWindowLongW(hFocusWindow, GWL_STYLE);
SetupWindowPosition(&winRect, dwStyle);
SetWindowPos(hFocusWindow, HWND_TOP, winRect.left, winRect.top, winRect.right - winRect.left,
winRect.bottom - winRect.top, 0);
HRESULT res = TrueCreateDevice(this, Adapter, DeviceType, hFocusWindow, BehaviorFlags,
pPresentationParameters, ppReturnedDeviceInterface);
if (res != S_OK) {
switch (res) {
case D3DERR_DEVICELOST:
log_error("D3D9", "CreateDevice failed: Device lost");
break;
case D3DERR_INVALIDCALL:
log_error("D3D9", "CreateDevice failed: Invalid call");
break;
case D3DERR_NOTAVAILABLE:
log_error("D3D9", "CreateDevice failed: Requested configuration not available");
break;
case D3DERR_OUTOFVIDEOMEMORY:
log_error("D3D9", "CreateDevice failed: VMem exhausted");
break;
default:
log_error("D3D9", "CreateDevice failed: %08x", res);
break;
}
}
return res;
}
IDirect3D9* WINAPI FakeDirect3DCreate9(UINT SDKVersion) {
IDirect3D9* pD3D = TrueDirect3DCreate9(D3D_SDK_VERSION);
hookType = UI_HOOK_DX9;
TrueCreateDevice = pD3D->lpVtbl->CreateDevice;
DWORD patch = (DWORD)&FakeCreateDevice;
patch_at(&pD3D->lpVtbl->CreateDevice, (char*)&patch, 4);
return pD3D;
};
int WINAPI FakeGetSystemMetrics(int nIndex) {
if (nIndex == SM_CXSCREEN && MiceConfig.window.w)
return MiceConfig.window.w;
else if (nIndex == SM_CYSCREEN && MiceConfig.window.h)
return MiceConfig.window.h;
return TrueGetSystemMetrics(nIndex);
}
void __cdecl Fake_glutFullScreen(void) {
hookType = UI_HOOK_GLUT;
if (!MiceConfig.window.windowed) True_glutFullScreen();
}
void __cdecl Fake_glutSwapBuffers(void) {
hookType = UI_HOOK_GLUT;
end_scene_hook_t* head = end_scene_hook_list;
while (head != NULL) {
head->hook(hookType, NULL);
head = head->next;
}
True_glutSwapBuffers();
}
LONG WINAPI FakeChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, DEVMODEW* lpDevMode, HWND hwnd,
DWORD dwflags, LPVOID lParam) {
if (MiceConfig.window.windowed) return DISP_CHANGE_SUCCESSFUL;
return TrueChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwflags, lParam);
}
void __cdecl Fake_glutInitDisplayMode(unsigned int mode) {
hookType = UI_HOOK_GLUT;
True_glutInitDisplayMode(mode);
}
void hook_gui() {
hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA);
hook("User32.dll", "CreateWindowExW", FakeCreateWindowExW, (void**)&TrueCreateWindowExW);
hook("User32.dll", "GetSystemMetrics", FakeGetSystemMetrics, (void**)&TrueGetSystemMetrics);
hook("User32.dll", "ChangeDisplaySettingsExW", FakeChangeDisplaySettingsExW,
(void**)&TrueChangeDisplaySettingsExW);
hook("D3d9.dll", "Direct3DCreate9", FakeDirect3DCreate9, (void**)&TrueDirect3DCreate9);
// Hooked as a way to identify use of GLUT
hook("FREEGLUT.DLL", "glutInitDisplayMode", Fake_glutInitDisplayMode,
(void**)&True_glutInitDisplayMode);
hook("FREEGLUT.DLL", "glutFullScreen", Fake_glutFullScreen, (void**)&True_glutFullScreen);
hook("FREEGLUT.DLL", "glutSwapBuffers", Fake_glutSwapBuffers, (void**)&True_glutSwapBuffers);
}