diff --git a/Makefile b/Makefile
index baab3fa..99e6501 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ FILES = src/debug.c \
src/settings.c \
src/lodepng.c \
src/dinput.c \
+ src/hook.c \
src/opengl.c
all:
diff --git a/cnc-ddraw.vcxproj b/cnc-ddraw.vcxproj
index e4f75cd..39864d4 100644
--- a/cnc-ddraw.vcxproj
+++ b/cnc-ddraw.vcxproj
@@ -14,6 +14,7 @@
+
@@ -29,8 +30,10 @@
+
+
diff --git a/cnc-ddraw.vcxproj.filters b/cnc-ddraw.vcxproj.filters
index 810b4c8..2423530 100644
--- a/cnc-ddraw.vcxproj.filters
+++ b/cnc-ddraw.vcxproj.filters
@@ -57,6 +57,9 @@
Source Files
+
+ Source Files
+
@@ -101,6 +104,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/inc/hook.h b/inc/hook.h
new file mode 100644
index 0000000..e4251e1
--- /dev/null
+++ b/inc/hook.h
@@ -0,0 +1,51 @@
+#ifndef HOOK_H
+#define HOOK_H
+
+#include
+
+typedef HFONT(__stdcall* CREATEFONTINDIRECTA)(CONST LOGFONT*);
+
+typedef BOOL (WINAPI* GETCURSORPOSPROC)(LPPOINT);
+typedef BOOL(WINAPI* CLIPCURSORPROC)(const RECT*);
+typedef int (WINAPI* SHOWCURSORPROC)(BOOL);
+typedef HCURSOR (WINAPI* SETCURSORPROC)(HCURSOR);
+typedef BOOL (WINAPI* GETWINDOWRECTPROC)(HWND, LPRECT);
+typedef BOOL (WINAPI* GETCLIENTRECTPROC)(HWND, LPRECT);
+typedef BOOL (WINAPI* CLIENTTOSCREENPROC)(HWND, LPPOINT);
+typedef BOOL (WINAPI* SCREENTOCLIENTPROC)(HWND, LPPOINT);
+typedef BOOL (WINAPI* SETCURSORPOSPROC)(int, int);
+typedef HWND (WINAPI* WINDOWFROMPOINTPROC)(POINT);
+typedef BOOL (WINAPI* GETCLIPCURSORPROC)(LPRECT);
+typedef BOOL (WINAPI* GETCURSORINFOPROC)(PCURSORINFO);
+typedef int (WINAPI* GETSYSTEMMETRICSPROC)(int);
+typedef BOOL (WINAPI* SETWINDOWPOSPROC)(HWND, HWND, int, int, int, int, UINT);
+typedef BOOL (WINAPI* MOVEWINDOWPROC)(HWND, int, int, int, int, BOOL);
+typedef LRESULT (WINAPI* SENDMESSAGEAPROC)(HWND, UINT, WPARAM, LPARAM);
+typedef LONG (WINAPI* SETWINDOWLONGAPROC)(HWND, int, LONG);
+
+extern GETCURSORPOSPROC real_GetCursorPos;
+extern CLIPCURSORPROC real_ClipCursor;
+extern SHOWCURSORPROC real_ShowCursor;
+extern SETCURSORPROC real_SetCursor;
+extern GETWINDOWRECTPROC real_GetWindowRect;
+extern GETCLIENTRECTPROC real_GetClientRect;
+extern CLIENTTOSCREENPROC real_ClientToScreen;
+extern SCREENTOCLIENTPROC real_ScreenToClient;
+extern SETCURSORPOSPROC real_SetCursorPos;
+extern WINDOWFROMPOINTPROC real_WindowFromPoint;
+extern GETCLIPCURSORPROC real_GetClipCursor;
+extern GETCURSORINFOPROC real_GetCursorInfo;
+extern GETSYSTEMMETRICSPROC real_GetSystemMetrics;
+extern SETWINDOWPOSPROC real_SetWindowPos;
+extern MOVEWINDOWPROC real_MoveWindow;
+extern SENDMESSAGEAPROC real_SendMessageA;
+extern SETWINDOWLONGAPROC real_SetWindowLongA;
+
+extern BOOL Hook_Active;
+
+void Hook_Init();
+void Hook_PatchIAT(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction);
+PROC Hook_HotPatch(PROC function, PROC newFunction);
+void Hook_TryHotPatch(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction, PROC *function);
+
+#endif
diff --git a/inc/main.h b/inc/main.h
index 4599e17..f4df6a2 100644
--- a/inc/main.h
+++ b/inc/main.h
@@ -125,6 +125,7 @@ typedef struct IDirectDrawImpl
BOOL altenter;
BOOL hidecursor;
BOOL accurateTimers;
+ BOOL hotPatch;
SpeedLimiter ticksLimiter;
SpeedLimiter flipLimiter;
SpeedLimiter fpsLimiter;
diff --git a/inc/mouse.h b/inc/mouse.h
new file mode 100644
index 0000000..dd18506
--- /dev/null
+++ b/inc/mouse.h
@@ -0,0 +1,27 @@
+#ifndef MOUSE_H
+#define MOUSE_H
+
+#include
+
+void mouse_lock();
+void mouse_unlock();
+
+BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint);
+BOOL WINAPI fake_ClipCursor(const RECT *lpRect);
+int WINAPI fake_ShowCursor(BOOL bShow);
+HCURSOR WINAPI fake_SetCursor(HCURSOR hCursor);
+BOOL WINAPI fake_GetWindowRect(HWND hWnd, LPRECT lpRect);
+BOOL WINAPI fake_GetClientRect(HWND hWnd, LPRECT lpRect);
+BOOL WINAPI fake_ClientToScreen(HWND hWnd, LPPOINT lpPoint);
+BOOL WINAPI fake_ScreenToClient(HWND hWnd, LPPOINT lpPoint);
+BOOL WINAPI fake_SetCursorPos(int X, int Y);
+HWND WINAPI fake_WindowFromPoint(POINT Point);
+BOOL WINAPI fake_GetClipCursor(LPRECT lpRect);
+BOOL WINAPI fake_GetCursorInfo(PCURSORINFO pci);
+int WINAPI fake_GetSystemMetrics(int nIndex);
+BOOL WINAPI fake_SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags);
+BOOL WINAPI fake_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint);
+LRESULT WINAPI fake_SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+LONG WINAPI fake_SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong);
+
+#endif
diff --git a/src/dinput.c b/src/dinput.c
index 5185c53..75579e6 100644
--- a/src/dinput.c
+++ b/src/dinput.c
@@ -1,7 +1,6 @@
#include
#include
-
-void HookIAT(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction);
+#include "hook.h"
typedef HRESULT (WINAPI *DInputCreateA)(HINSTANCE, DWORD, LPDIRECTINPUTA*, LPUNKNOWN);
typedef HRESULT (WINAPI *DICreateDevice)(IDirectInputA*, REFGUID, LPDIRECTINPUTDEVICEA *, LPUNKNOWN);
@@ -64,5 +63,5 @@ static HRESULT WINAPI fake_DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion,
void dinput_init()
{
- HookIAT(GetModuleHandle(NULL), "dinput.dll", "DirectInputCreateA", (PROC)fake_DirectInputCreateA);
+ Hook_PatchIAT(GetModuleHandle(NULL), "dinput.dll", "DirectInputCreateA", (PROC)fake_DirectInputCreateA);
}
diff --git a/src/hook.c b/src/hook.c
new file mode 100644
index 0000000..d85febe
--- /dev/null
+++ b/src/hook.c
@@ -0,0 +1,190 @@
+#include
+#include
+#include "main.h"
+#include "mouse.h"
+#include "hook.h"
+
+BOOL Hook_Active;
+GETCURSORPOSPROC real_GetCursorPos = GetCursorPos;
+CLIPCURSORPROC real_ClipCursor = ClipCursor;
+SHOWCURSORPROC real_ShowCursor = ShowCursor;
+SETCURSORPROC real_SetCursor = SetCursor;
+GETWINDOWRECTPROC real_GetWindowRect = GetWindowRect;
+GETCLIENTRECTPROC real_GetClientRect = GetClientRect;
+CLIENTTOSCREENPROC real_ClientToScreen = ClientToScreen;
+SCREENTOCLIENTPROC real_ScreenToClient = ScreenToClient;
+SETCURSORPOSPROC real_SetCursorPos = SetCursorPos;
+WINDOWFROMPOINTPROC real_WindowFromPoint = WindowFromPoint;
+GETCLIPCURSORPROC real_GetClipCursor = GetClipCursor;
+GETCURSORINFOPROC real_GetCursorInfo = GetCursorInfo;
+GETSYSTEMMETRICSPROC real_GetSystemMetrics = GetSystemMetrics;
+SETWINDOWPOSPROC real_SetWindowPos = SetWindowPos;
+MOVEWINDOWPROC real_MoveWindow = MoveWindow;
+SENDMESSAGEAPROC real_SendMessageA = SendMessageA;
+SETWINDOWLONGAPROC real_SetWindowLongA = SetWindowLongA;
+
+void Hook_PatchIAT(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction)
+{
+ if (!hMod || hMod == INVALID_HANDLE_VALUE || !newFunction)
+ return;
+
+ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
+ if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+ return;
+
+ PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew);
+ if (pNTHeaders->Signature != IMAGE_NT_SIGNATURE)
+ return;
+
+ PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDosHeader +
+ (DWORD)(pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
+
+ if (pImportDescriptor == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeaders)
+ return;
+
+ while (pImportDescriptor->FirstThunk)
+ {
+ char *impModuleName = (char *)((DWORD)pDosHeader + (DWORD)(pImportDescriptor->Name));
+
+ if (_stricmp(impModuleName, moduleName) == 0)
+ {
+ PIMAGE_THUNK_DATA pFirstThunk =
+ (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + (DWORD)pImportDescriptor->FirstThunk);
+
+ PIMAGE_THUNK_DATA pOrigFirstThunk =
+ (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + (DWORD)pImportDescriptor->OriginalFirstThunk);
+
+ while (pFirstThunk->u1.Function && pOrigFirstThunk->u1.AddressOfData)
+ {
+ PIMAGE_IMPORT_BY_NAME pImport =
+ (PIMAGE_IMPORT_BY_NAME)((DWORD)pDosHeader + pOrigFirstThunk->u1.AddressOfData);
+
+ if ((pOrigFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0 &&
+ _stricmp((const char *)pImport->Name, functionName) == 0)
+ {
+ DWORD oldProtect;
+
+ if (VirtualProtect(&pFirstThunk->u1.Function, sizeof(DWORD), PAGE_READWRITE, &oldProtect))
+ {
+ pFirstThunk->u1.Function = (DWORD)newFunction;
+ VirtualProtect(&pFirstThunk->u1.Function, sizeof(DWORD), oldProtect, &oldProtect);
+ }
+
+ break;
+ }
+
+ pFirstThunk++;
+ pOrigFirstThunk++;
+ }
+ }
+
+ pImportDescriptor++;
+ }
+}
+
+PROC Hook_HotPatch(PROC function, PROC newFunction)
+{
+ PROC result = function;
+
+ unsigned short *bytes = (unsigned short *)function;
+ if (function && *bytes == 0xFF8B) // mov edi, edi
+ {
+ char *address = ((char *)function) - 5;
+ DWORD oldProtect;
+
+ if (VirtualProtect(address, 7, PAGE_EXECUTE_READWRITE, &oldProtect))
+ {
+ if (memcmp(address, (const char[]) { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }, 5) == 0 ||
+ memcmp(address, (const char[]) { 0x90, 0x90, 0x90, 0x90, 0x90 }, 5) == 0)
+ {
+ address[0] = 0xE9; // long jump
+ *((DWORD *)(&address[1])) = ((char *)newFunction) - address - 5;
+ *((WORD *)(&address[5])) = 0xF9EB; // short jump to our long jump
+
+ result = (PROC)(((char *)function) + 2);
+ }
+
+ VirtualProtect(address, 7, oldProtect, &oldProtect);
+ }
+ }
+
+ return result;
+}
+
+void Hook_TryHotPatch(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction, PROC *function)
+{
+ PROC org = GetProcAddress(GetModuleHandle(moduleName), functionName);
+ if (org)
+ {
+ *function = Hook_HotPatch(org, newFunction);
+
+ if (*function == org) // hotpatch failed...
+ Hook_PatchIAT(hMod, moduleName, functionName, newFunction);
+ }
+}
+
+void Hook_Init()
+{
+ if (!Hook_Active)
+ {
+ Hook_Active = TRUE;
+
+ if (ddraw->hotPatch)
+ {
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "GetCursorPos", (PROC)fake_GetCursorPos, (PROC *)&real_GetCursorPos);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "ClipCursor", (PROC)fake_ClipCursor, (PROC *)&real_ClipCursor);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "ShowCursor", (PROC)fake_ShowCursor, (PROC *)&real_ShowCursor);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "SetCursor", (PROC)fake_SetCursor, (PROC *)&real_SetCursor);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "GetWindowRect", (PROC)fake_GetWindowRect, (PROC *)&real_GetWindowRect);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "GetClientRect", (PROC)fake_GetClientRect, (PROC *)&real_GetClientRect);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "ClientToScreen", (PROC)fake_ClientToScreen, (PROC *)&real_ClientToScreen);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "ScreenToClient", (PROC)fake_ScreenToClient, (PROC *)&real_ScreenToClient);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "SetCursorPos", (PROC)fake_SetCursorPos, (PROC *)&real_SetCursorPos);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "GetClipCursor", (PROC)fake_GetClipCursor, (PROC *)&real_GetClipCursor);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "WindowFromPoint", (PROC)fake_WindowFromPoint, (PROC *)&real_WindowFromPoint);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "GetCursorInfo", (PROC)fake_GetCursorInfo, (PROC *)&real_GetCursorInfo);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "GetSystemMetrics", (PROC)fake_GetSystemMetrics, (PROC *)&real_GetSystemMetrics);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "SetWindowPos", (PROC)fake_SetWindowPos, (PROC *)&real_SetWindowPos);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "MoveWindow", (PROC)fake_MoveWindow, (PROC *)&real_MoveWindow);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "SendMessageA", (PROC)fake_SendMessageA, (PROC *)&real_SendMessageA);
+ Hook_TryHotPatch(
+ GetModuleHandle(NULL), "user32.dll", "SetWindowLongA", (PROC)fake_SetWindowLongA, (PROC *)&real_SetWindowLongA);
+ }
+ else
+ {
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "GetCursorPos", (PROC)fake_GetCursorPos);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "ClipCursor", (PROC)fake_ClipCursor);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "ShowCursor", (PROC)fake_ShowCursor);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "SetCursor", (PROC)fake_SetCursor);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "GetWindowRect", (PROC)fake_GetWindowRect);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "GetClientRect", (PROC)fake_GetClientRect);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "ClientToScreen", (PROC)fake_ClientToScreen);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "ScreenToClient", (PROC)fake_ScreenToClient);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "SetCursorPos", (PROC)fake_SetCursorPos);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "GetClipCursor", (PROC)fake_GetClipCursor);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "WindowFromPoint", (PROC)fake_WindowFromPoint);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "GetCursorInfo", (PROC)fake_GetCursorInfo);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "GetSystemMetrics", (PROC)fake_GetSystemMetrics);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "SetWindowPos", (PROC)fake_SetWindowPos);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "MoveWindow", (PROC)fake_MoveWindow);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "SendMessageA", (PROC)fake_SendMessageA);
+ Hook_PatchIAT(GetModuleHandle(NULL), "user32.dll", "SetWindowLongA", (PROC)fake_SetWindowLongA);
+ }
+ }
+}
diff --git a/src/main.c b/src/main.c
index f181922..ad875df 100644
--- a/src/main.c
+++ b/src/main.c
@@ -27,15 +27,12 @@
#include "palette.h"
#include "surface.h"
#include "clipper.h"
+#include "hook.h"
+#include "mouse.h"
#include "render_d3d9.h"
#define IDR_MYMENU 93
-BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint);
-void mouse_init();
-void mouse_lock();
-void mouse_unlock();
-
BOOL screenshot(struct IDirectDrawSurfaceImpl *);
void Settings_Load();
void Settings_Save(RECT *lpRect, int windowState);
@@ -115,7 +112,7 @@ BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam)
RECT size;
RECT pos;
- if (GetClientRect(hWnd, &size) && GetWindowRect(hWnd, &pos) && size.right > 1 && size.bottom > 1)
+ if (real_GetClientRect(hWnd, &size) && real_GetWindowRect(hWnd, &pos) && size.right > 1 && size.bottom > 1)
{
ChildWindowExists = TRUE;
@@ -552,13 +549,13 @@ HRESULT __stdcall ddraw_SetDisplayMode(IDirectDrawImpl *This, DWORD width, DWORD
return DDERR_UNSUPPORTED;
}
- const HANDLE hbicon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDR_MYMENU), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0);
+ const HANDLE hbicon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDR_MYMENU), IMAGE_ICON, real_GetSystemMetrics(SM_CXICON), real_GetSystemMetrics(SM_CYICON), 0);
if (hbicon)
- SendMessage(This->hWnd, WM_SETICON, ICON_BIG, (LPARAM)hbicon);
+ real_SendMessageA(This->hWnd, WM_SETICON, ICON_BIG, (LPARAM)hbicon);
- const HANDLE hsicon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDR_MYMENU), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
+ const HANDLE hsicon = LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDR_MYMENU), IMAGE_ICON, real_GetSystemMetrics(SM_CXSMICON), real_GetSystemMetrics(SM_CYSMICON), 0);
if (hsicon)
- SendMessage(This->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hsicon);
+ real_SendMessageA(This->hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hsicon);
}
if (ddraw->altenter)
@@ -764,23 +761,23 @@ HRESULT __stdcall ddraw_SetDisplayMode(IDirectDrawImpl *This, DWORD width, DWORD
{
if (!This->border)
{
- SetWindowLong(This->hWnd, GWL_STYLE, GetWindowLong(This->hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU));
+ real_SetWindowLongA(This->hWnd, GWL_STYLE, GetWindowLong(This->hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU));
}
else
{
- SetWindowLong(This->hWnd, GWL_STYLE, (GetWindowLong(This->hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW) & ~WS_MAXIMIZEBOX);
+ real_SetWindowLongA(This->hWnd, GWL_STYLE, (GetWindowLong(This->hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW) & ~WS_MAXIMIZEBOX);
}
if (ddraw->wine)
- SetWindowLong(This->hWnd, GWL_STYLE, (GetWindowLong(This->hWnd, GWL_STYLE) | WS_MINIMIZEBOX) & ~(WS_MAXIMIZEBOX | WS_THICKFRAME));
+ real_SetWindowLongA(This->hWnd, GWL_STYLE, (GetWindowLong(This->hWnd, GWL_STYLE) | WS_MINIMIZEBOX) & ~(WS_MAXIMIZEBOX | WS_THICKFRAME));
/* center the window with correct dimensions */
int x = (WindowRect.left != -32000) ? WindowRect.left : (This->mode.dmPelsWidth / 2) - (This->render.width / 2);
int y = (WindowRect.top != -32000) ? WindowRect.top : (This->mode.dmPelsHeight / 2) - (This->render.height / 2);
RECT dst = { x, y, This->render.width + x, This->render.height + y };
AdjustWindowRect(&dst, GetWindowLong(This->hWnd, GWL_STYLE), FALSE);
- SetWindowPos(ddraw->hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- MoveWindow(This->hWnd, dst.left, dst.top, (dst.right - dst.left), (dst.bottom - dst.top), TRUE);
+ real_SetWindowPos(ddraw->hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ real_MoveWindow(This->hWnd, dst.left, dst.top, (dst.right - dst.left), (dst.bottom - dst.top), TRUE);
if (This->renderer == render_d3d9_main)
InitDirect3D9();
@@ -800,9 +797,9 @@ HRESULT __stdcall ddraw_SetDisplayMode(IDirectDrawImpl *This, DWORD width, DWORD
}
if (ddraw->wine)
- SetWindowLong(This->hWnd, GWL_STYLE, GetWindowLong(This->hWnd, GWL_STYLE) | WS_MINIMIZEBOX);
+ real_SetWindowLongA(This->hWnd, GWL_STYLE, GetWindowLong(This->hWnd, GWL_STYLE) | WS_MINIMIZEBOX);
- SetWindowPos(This->hWnd, HWND_TOPMOST, 0, 0, This->render.width, This->render.height, SWP_SHOWWINDOW);
+ real_SetWindowPos(This->hWnd, HWND_TOPMOST, 0, 0, This->render.width, This->render.height, SWP_SHOWWINDOW);
LastSetWindowPosTick = timeGetTime();
mouse_lock();
@@ -840,7 +837,7 @@ void ToggleFullscreen()
{
mouse_unlock();
WindowState = ddraw->windowed = FALSE;
- SetWindowLong(ddraw->hWnd, GWL_STYLE, GetWindowLong(ddraw->hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU));
+ real_SetWindowLongA(ddraw->hWnd, GWL_STYLE, GetWindowLong(ddraw->hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU));
ddraw->altenter = TRUE;
ddraw_SetDisplayMode(ddraw, ddraw->width, ddraw->height, ddraw->bpp);
mouse_lock();
@@ -951,8 +948,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (!ddraw->windowed)
{
LastSetWindowPosTick = timeGetTime();
- SetWindowPos(ddraw->hWnd, HWND_TOPMOST, 1, 1, ddraw->render.width, ddraw->render.height, SWP_SHOWWINDOW);
- SetWindowPos(ddraw->hWnd, HWND_TOPMOST, 0, 0, ddraw->render.width, ddraw->render.height, SWP_SHOWWINDOW);
+ real_SetWindowPos(ddraw->hWnd, HWND_TOPMOST, 1, 1, ddraw->render.width, ddraw->render.height, SWP_SHOWWINDOW);
+ real_SetWindowPos(ddraw->hWnd, HWND_TOPMOST, 0, 0, ddraw->render.width, ddraw->render.height, SWP_SHOWWINDOW);
}
return 0;
}
@@ -1248,8 +1245,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_AUTORENDERER:
{
mouse_unlock();
- SetWindowPos(ddraw->hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- SetWindowPos(ddraw->hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ real_SetWindowPos(ddraw->hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ real_SetWindowPos(ddraw->hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
if (!ddraw->wine)
{
ShowWindow(ddraw->hWnd, SW_MINIMIZE);
@@ -1414,11 +1411,11 @@ HRESULT __stdcall ddraw_SetCooperativeLevel(IDirectDrawImpl *This, HWND hWnd, DW
if (!This->WndProc)
{
- mouse_init();
+ Hook_Init();
This->WndProc = (LRESULT(CALLBACK *)(HWND, UINT, WPARAM, LPARAM))GetWindowLong(hWnd, GWL_WNDPROC);
- SetWindowLong(This->hWnd, GWL_WNDPROC, (LONG)WndProc);
+ real_SetWindowLongA(This->hWnd, GWL_WNDPROC, (LONG)WndProc);
if (!This->render.hDC)
{
@@ -1436,11 +1433,11 @@ HRESULT __stdcall ddraw_SetCooperativeLevel(IDirectDrawImpl *This, HWND hWnd, DW
if (ddraw->handlemouse && ddraw->windowed)
{
- while (ShowCursor(FALSE) > 0); //workaround for direct input games
- while (ShowCursor(TRUE) < 0);
+ while (real_ShowCursor(FALSE) > 0); //workaround for direct input games
+ while (real_ShowCursor(TRUE) < 0);
}
- SetCursor(LoadCursor(NULL, IDC_ARROW));
+ real_SetCursor(LoadCursor(NULL, IDC_ARROW));
GetWindowText(This->hWnd, (LPTSTR)&This->title, sizeof(This->title));
@@ -1559,7 +1556,7 @@ ULONG __stdcall ddraw_Release(IDirectDrawImpl *This)
DeleteCriticalSection(&This->cs);
/* restore old wndproc, subsequent ddraw creation will otherwise fail */
- SetWindowLong(This->hWnd, GWL_WNDPROC, (LONG)This->WndProc);
+ real_SetWindowLongA(This->hWnd, GWL_WNDPROC, (LONG)This->WndProc);
HeapFree(GetProcessHeap(), 0, This);
ddraw = NULL;
return 0;
diff --git a/src/mouse.c b/src/mouse.c
index 01be2b8..9b73e7f 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -14,27 +14,25 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* This is a special mouse coordinate fix for games that use GetCursorPos and expect to be in fullscreen */
-
#include
#include
#include "main.h"
#include "surface.h"
+#include "hook.h"
-BOOL mouse_active = FALSE;
int yAdjust = 0;
BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint)
{
POINT pt, realpt;
- if (!GetCursorPos(&pt) || !ddraw)
+ if (!real_GetCursorPos(&pt) || !ddraw)
return FALSE;
realpt.x = pt.x;
realpt.y = pt.y;
- if(ddraw->locked && (!ddraw->windowed || ScreenToClient(ddraw->hWnd, &pt)))
+ if(ddraw->locked && (!ddraw->windowed || real_ScreenToClient(ddraw->hWnd, &pt)))
{
//fallback solution for possible ClipCursor failure
int diffx = 0, diffy = 0;
@@ -66,7 +64,7 @@ BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint)
}
if (diffx || diffy)
- SetCursorPos(realpt.x - diffx, realpt.y - diffy);
+ real_SetCursorPos(realpt.x - diffx, realpt.y - diffy);
if(ddraw->adjmouse)
@@ -98,7 +96,7 @@ BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint)
}
if (diffx || diffy)
- SetCursorPos(realpt.x - diffx, realpt.y - diffy);
+ real_SetCursorPos(realpt.x - diffx, realpt.y - diffy);
}
}
@@ -127,7 +125,7 @@ int WINAPI fake_ShowCursor(BOOL bShow)
static int count;
if (ddraw && !ddraw->handlemouse)
- return ShowCursor(bShow);
+ return real_ShowCursor(bShow);
return bShow ? ++count : --count;
}
@@ -135,70 +133,11 @@ int WINAPI fake_ShowCursor(BOOL bShow)
HCURSOR WINAPI fake_SetCursor(HCURSOR hCursor)
{
if (ddraw && !ddraw->handlemouse)
- return SetCursor(hCursor);
+ return real_SetCursor(hCursor);
return NULL;
}
-void HookIAT(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction)
-{
- if (!hMod || hMod == INVALID_HANDLE_VALUE || !newFunction)
- return;
-
- PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
- if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
- return;
-
- PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew);
- if (pNTHeaders->Signature != IMAGE_NT_SIGNATURE)
- return;
-
- PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDosHeader +
- (DWORD)(pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
-
- if (pImportDescriptor == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeaders)
- return;
-
- while (pImportDescriptor->FirstThunk)
- {
- char *impModuleName = (char *)((DWORD)pDosHeader + (DWORD)(pImportDescriptor->Name));
-
- if (_stricmp(impModuleName, moduleName) == 0)
- {
- PIMAGE_THUNK_DATA pFirstThunk =
- (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + (DWORD)pImportDescriptor->FirstThunk);
-
- PIMAGE_THUNK_DATA pOrigFirstThunk =
- (PIMAGE_THUNK_DATA)((DWORD)pDosHeader + (DWORD)pImportDescriptor->OriginalFirstThunk);
-
- while (pFirstThunk->u1.Function && pOrigFirstThunk->u1.AddressOfData)
- {
- PIMAGE_IMPORT_BY_NAME pImport =
- (PIMAGE_IMPORT_BY_NAME)((DWORD)pDosHeader + pOrigFirstThunk->u1.AddressOfData);
-
- if ((pOrigFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0 &&
- _stricmp((const char *)pImport->Name, functionName) == 0)
- {
- DWORD oldProtect;
-
- if (VirtualProtect(&pFirstThunk->u1.Function, sizeof(DWORD), PAGE_READWRITE, &oldProtect))
- {
- pFirstThunk->u1.Function = (DWORD)newFunction;
- VirtualProtect(&pFirstThunk->u1.Function, sizeof(DWORD), oldProtect, &oldProtect);
- }
-
- break;
- }
-
- pFirstThunk++;
- pOrigFirstThunk++;
- }
- }
-
- pImportDescriptor++;
- }
-}
-
void mouse_lock()
{
RECT rc;
@@ -206,15 +145,15 @@ void mouse_lock()
if (ddraw->devmode)
{
if (ddraw->handlemouse)
- while(ShowCursor(FALSE) > 0);
+ while(real_ShowCursor(FALSE) > 0);
return;
}
- if (mouse_active && !ddraw->locked)
+ if (Hook_Active && !ddraw->locked)
{
// Get the window client area.
- GetClientRect(ddraw->hWnd, &rc);
+ real_GetClientRect(ddraw->hWnd, &rc);
if(ddraw->adjmouse)
{
@@ -230,8 +169,8 @@ void mouse_lock()
// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
- ClientToScreen(ddraw->hWnd, &pt);
- ClientToScreen(ddraw->hWnd, &pt2);
+ real_ClientToScreen(ddraw->hWnd, &pt);
+ real_ClientToScreen(ddraw->hWnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
@@ -239,29 +178,29 @@ void mouse_lock()
if(ddraw->adjmouse)
{
- SetCursorPos(
+ real_SetCursorPos(
rc.left + (ddraw->cursor.x * ddraw->render.scaleW),
rc.top + ((ddraw->cursor.y - yAdjust) * ddraw->render.scaleH));
}
else
{
- SetCursorPos(rc.left + ddraw->cursor.x, rc.top + ddraw->cursor.y - yAdjust);
+ real_SetCursorPos(rc.left + ddraw->cursor.x, rc.top + ddraw->cursor.y - yAdjust);
}
if (ddraw->handlemouse)
{
SetCapture(ddraw->hWnd);
- ClipCursor(&rc);
- while (ShowCursor(FALSE) > 0);
+ real_ClipCursor(&rc);
+ while (real_ShowCursor(FALSE) > 0);
}
else
{
if (ddraw->hidecursor)
{
ddraw->hidecursor = FALSE;
- ShowCursor(FALSE);
+ real_ShowCursor(FALSE);
}
- ClipCursor(&rc);
+ real_ClipCursor(&rc);
}
ddraw->locked = TRUE;
@@ -275,12 +214,12 @@ void mouse_unlock()
if (ddraw->devmode)
{
if (ddraw->handlemouse)
- while(ShowCursor(TRUE) < 0);
+ while(real_ShowCursor(TRUE) < 0);
return;
}
- if(!mouse_active)
+ if(!Hook_Active)
{
return;
}
@@ -290,34 +229,34 @@ void mouse_unlock()
ddraw->locked = FALSE;
// Get the window client area.
- GetClientRect(ddraw->hWnd, &rc);
+ real_GetClientRect(ddraw->hWnd, &rc);
// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
- ClientToScreen(ddraw->hWnd, &pt);
- ClientToScreen(ddraw->hWnd, &pt2);
+ real_ClientToScreen(ddraw->hWnd, &pt);
+ real_ClientToScreen(ddraw->hWnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
if (ddraw->handlemouse)
{
- while (ShowCursor(TRUE) < 0);
- SetCursor(LoadCursor(NULL, IDC_ARROW));
+ while (real_ShowCursor(TRUE) < 0);
+ real_SetCursor(LoadCursor(NULL, IDC_ARROW));
}
else
{
CURSORINFO ci = { .cbSize = sizeof(CURSORINFO) };
- if (GetCursorInfo(&ci) && ci.flags == 0)
+ if (real_GetCursorInfo(&ci) && ci.flags == 0)
{
ddraw->hidecursor = TRUE;
- while (ShowCursor(TRUE) < 0);
+ while (real_ShowCursor(TRUE) < 0);
}
}
- ClipCursor(NULL);
+ real_ClipCursor(NULL);
ReleaseCapture();
- SetCursorPos(
+ real_SetCursorPos(
rc.left + ddraw->render.viewport.x + (ddraw->cursor.x * ddraw->render.scaleW),
rc.top + ddraw->render.viewport.y + ((ddraw->cursor.y + yAdjust) * ddraw->render.scaleH));
}
@@ -338,11 +277,11 @@ BOOL WINAPI fake_GetWindowRect(HWND hWnd, LPRECT lpRect)
}
else
{
- return GetWindowRect(hWnd, lpRect) && MapWindowPoints(HWND_DESKTOP, ddraw->hWnd, (LPPOINT)lpRect, 2);
+ return real_GetWindowRect(hWnd, lpRect) && MapWindowPoints(HWND_DESKTOP, ddraw->hWnd, (LPPOINT)lpRect, 2);
}
}
- return GetWindowRect(hWnd, lpRect);
+ return real_GetWindowRect(hWnd, lpRect);
}
BOOL WINAPI fake_GetClientRect(HWND hWnd, LPRECT lpRect)
@@ -357,13 +296,13 @@ BOOL WINAPI fake_GetClientRect(HWND hWnd, LPRECT lpRect)
return TRUE;
}
- return GetClientRect(hWnd, lpRect);
+ return real_GetClientRect(hWnd, lpRect);
}
BOOL WINAPI fake_ClientToScreen(HWND hWnd, LPPOINT lpPoint)
{
if (ddraw && ddraw->hWnd != hWnd)
- return ClientToScreen(hWnd, lpPoint) && ScreenToClient(ddraw->hWnd, lpPoint);
+ return real_ClientToScreen(hWnd, lpPoint) && real_ScreenToClient(ddraw->hWnd, lpPoint);
return TRUE;
}
@@ -371,7 +310,7 @@ BOOL WINAPI fake_ClientToScreen(HWND hWnd, LPPOINT lpPoint)
BOOL WINAPI fake_ScreenToClient(HWND hWnd, LPPOINT lpPoint)
{
if (ddraw && ddraw->hWnd != hWnd)
- return ClientToScreen(ddraw->hWnd, lpPoint) && ScreenToClient(hWnd, lpPoint);
+ return real_ClientToScreen(ddraw->hWnd, lpPoint) && real_ScreenToClient(hWnd, lpPoint);
return TRUE;
}
@@ -379,13 +318,13 @@ BOOL WINAPI fake_ScreenToClient(HWND hWnd, LPPOINT lpPoint)
BOOL WINAPI fake_SetCursorPos(int X, int Y)
{
POINT pt = { X, Y };
- return ddraw && ClientToScreen(ddraw->hWnd, &pt) && SetCursorPos(pt.x, pt.y);
+ return ddraw && real_ClientToScreen(ddraw->hWnd, &pt) && real_SetCursorPos(pt.x, pt.y);
}
HWND WINAPI fake_WindowFromPoint(POINT Point)
{
POINT pt = { Point.x, Point.y };
- return ddraw && ClientToScreen(ddraw->hWnd, &pt) ? WindowFromPoint(pt) : NULL;
+ return ddraw && real_ClientToScreen(ddraw->hWnd, &pt) ? real_WindowFromPoint(pt) : NULL;
}
BOOL WINAPI fake_GetClipCursor(LPRECT lpRect)
@@ -405,7 +344,7 @@ BOOL WINAPI fake_GetClipCursor(LPRECT lpRect)
BOOL WINAPI fake_GetCursorInfo(PCURSORINFO pci)
{
- return pci && ddraw && GetCursorInfo(pci) && ScreenToClient(ddraw->hWnd, &pci->ptScreenPos);
+ return pci && ddraw && real_GetCursorInfo(pci) && real_ScreenToClient(ddraw->hWnd, &pci->ptScreenPos);
}
int WINAPI fake_GetSystemMetrics(int nIndex)
@@ -419,7 +358,7 @@ int WINAPI fake_GetSystemMetrics(int nIndex)
return ddraw->height;
}
- return GetSystemMetrics(nIndex);
+ return real_GetSystemMetrics(nIndex);
}
BOOL WINAPI fake_SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags)
@@ -427,7 +366,7 @@ BOOL WINAPI fake_SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int
if (ddraw && ddraw->hWnd == hWnd)
return TRUE;
- return SetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
+ return real_SetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
}
BOOL WINAPI fake_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
@@ -435,12 +374,12 @@ BOOL WINAPI fake_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BO
if (ddraw && ddraw->hWnd == hWnd)
return TRUE;
- return MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
+ return real_MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
}
LRESULT WINAPI fake_SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
- LRESULT result = SendMessageA(hWnd, Msg, wParam, lParam);
+ LRESULT result = real_SendMessageA(hWnd, Msg, wParam, lParam);
if (result && ddraw && Msg == CB_GETDROPPEDCONTROLRECT)
{
@@ -457,27 +396,5 @@ LONG WINAPI fake_SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong)
if (ddraw && ddraw->hWnd == hWnd && nIndex == GWL_STYLE)
return 0;
- return SetWindowLongA(hWnd, nIndex, dwNewLong);
-}
-
-void mouse_init()
-{
- HookIAT(GetModuleHandle(NULL), "user32.dll", "GetCursorPos", (PROC)fake_GetCursorPos);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "ClipCursor", (PROC)fake_ClipCursor);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "ShowCursor", (PROC)fake_ShowCursor);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "SetCursor", (PROC)fake_SetCursor);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "GetWindowRect", (PROC)fake_GetWindowRect);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "GetClientRect", (PROC)fake_GetClientRect);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "ClientToScreen", (PROC)fake_ClientToScreen);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "ScreenToClient", (PROC)fake_ScreenToClient);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "SetCursorPos", (PROC)fake_SetCursorPos);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "GetClipCursor", (PROC)fake_GetClipCursor);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "WindowFromPoint", (PROC)fake_WindowFromPoint);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "GetCursorInfo", (PROC)fake_GetCursorInfo);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "GetSystemMetrics", (PROC)fake_GetSystemMetrics);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "SetWindowPos", (PROC)fake_SetWindowPos);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "MoveWindow", (PROC)fake_MoveWindow);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "SendMessageA", (PROC)fake_SendMessageA);
- HookIAT(GetModuleHandle(NULL), "user32.dll", "SetWindowLongA", (PROC)fake_SetWindowLongA);
- mouse_active = TRUE;
+ return real_SetWindowLongA(hWnd, nIndex, dwNewLong);
}
diff --git a/src/settings.c b/src/settings.c
index f01b270..d2ef3e9 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -41,6 +41,7 @@ void Settings_Load()
ddraw->noactivateapp = GetBool("noactivateapp", FALSE);
ddraw->vhack = GetBool("vhack", FALSE);
ddraw->accurateTimers = GetBool("accuratetimers", FALSE);
+ ddraw->hotPatch = GetBool("hotPatch", FALSE);
WindowRect.right = GetInt("width", 0);
WindowRect.bottom = GetInt("height", 0);
@@ -274,6 +275,9 @@ static void CreateSettingsIni()
"; Force CPU0 affinity, avoids crashes/freezing, *might* have a performance impact\n"
"singlecpu=true\n"
"\n"
+ "; Use hotpatching rather than IAT hooking\n"
+ "; Note: Can be used to fix issues related to new features added by cnc-ddraw such as windowed mode or stretching\n"
+ "hotPatch=false\n"
"\n"
"\n"
"; ### Game specific settings ###\n"
diff --git a/src/surface.c b/src/surface.c
index 27d8088..f83f5f6 100644
--- a/src/surface.c
+++ b/src/surface.c
@@ -18,6 +18,7 @@
#include
#include "main.h"
+#include "hook.h"
#include "surface.h"
#include "scale_pattern.h"