1
0
mirror of https://github.com/FunkyFr3sh/cnc-ddraw.git synced 2025-03-25 10:07:47 +01:00
cnc-ddraw/src/utils.c

950 lines
27 KiB
C
Raw Normal View History

2020-10-13 09:20:52 +02:00
#include <windows.h>
2022-09-19 13:13:34 +02:00
#include <intrin.h>
2023-12-29 01:40:49 +01:00
#include <math.h>
#include "ddraw.h"
#include "debug.h"
2020-10-13 09:20:52 +02:00
#include "dd.h"
#include "ddsurface.h"
#include "hook.h"
#include "mouse.h"
#include "render_d3d9.h"
#include "utils.h"
#include "config.h"
/*
The following code is licensed under the MIT license:
DetourEnumerateModules
Copyright (c) Microsoft Corporation
https://github.com/microsoft/Detours
*/
#define MM_ALLOCATION_GRANULARITY 0x10000
HMODULE WINAPI util_enumerate_modules(_In_opt_ HMODULE hModuleLast)
{
PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
MEMORY_BASIC_INFORMATION mbi;
ZeroMemory(&mbi, sizeof(mbi));
// Find the next memory region that contains a mapped PE image.
//
for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
if (VirtualQuery(pbLast, &mbi, sizeof(mbi)) <= 0) {
break;
}
// Skip uncommitted regions and guard pages.
//
if ((mbi.State != MEM_COMMIT) ||
((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
(mbi.Protect & PAGE_GUARD)) {
continue;
}
__try {
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ||
(DWORD)pDosHeader->e_lfanew > mbi.RegionSize ||
(DWORD)pDosHeader->e_lfanew < sizeof(*pDosHeader)) {
continue;
}
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
continue;
}
return (HMODULE)pDosHeader;
}
#if defined(_MSC_VER)
#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
#endif
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
continue;
}
}
return NULL;
}
2024-07-13 22:47:40 +02:00
FARPROC util_get_iat_proc(HMODULE mod, char* module_name, char* function_name)
{
2024-07-13 22:47:40 +02:00
if (!mod || mod == INVALID_HANDLE_VALUE)
return NULL;
__try
{
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)mod;
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
PIMAGE_NT_HEADERS nt_headers = (PIMAGE_NT_HEADERS)((DWORD)dos_header + (DWORD)dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
return NULL;
DWORD import_desc_rva = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
DWORD import_desc_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if (import_desc_rva == 0 || import_desc_size == 0)
return NULL;
PIMAGE_IMPORT_DESCRIPTOR import_desc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)dos_header + import_desc_rva);
while (import_desc->FirstThunk)
{
if (!import_desc->OriginalFirstThunk || !import_desc->Name)
{
import_desc++;
continue;
}
char* imp_module_name = (char*)((DWORD)dos_header + import_desc->Name);
if (_stricmp(imp_module_name, module_name) == 0)
{
PIMAGE_THUNK_DATA first_thunk = (void*)((DWORD)dos_header + import_desc->FirstThunk);
PIMAGE_THUNK_DATA o_first_thunk = (void*)((DWORD)dos_header + import_desc->OriginalFirstThunk);
while (first_thunk->u1.Function)
{
if (!o_first_thunk->u1.AddressOfData)
{
first_thunk++;
o_first_thunk++;
continue;
}
PIMAGE_IMPORT_BY_NAME import = (void*)((DWORD)dos_header + o_first_thunk->u1.AddressOfData);
if ((o_first_thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0)
{
#if defined(__GNUC__)
if (util_is_bad_read_ptr((void*)import->Name))
continue;
#endif
if (strcmp((const char*)import->Name, function_name) == 0 && first_thunk->u1.Function)
{
return (FARPROC)first_thunk->u1.Function;
}
}
first_thunk++;
o_first_thunk++;
}
}
import_desc++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
return NULL;
}
BOOL util_caller_is_ddraw_wrapper(void* return_address)
{
BOOL (WINAPI *getModuleHandleExA)(DWORD, LPCSTR, HMODULE*) =
2024-07-14 00:09:03 +02:00
(void*)real_GetProcAddress(GetModuleHandleA("Kernel32.dll"), "GetModuleHandleExA");
if (!getModuleHandleExA)
return FALSE;
2024-07-13 22:47:40 +02:00
void* directDrawCreate = util_get_iat_proc(GetModuleHandleA(NULL), "ddraw.dll", "DirectDrawCreate");
void* directDrawCreateEx = util_get_iat_proc(GetModuleHandleA(NULL), "ddraw.dll", "DirectDrawCreateEx");
TRACE("%s directDrawCreate = %p, directDrawCreateEx = %p\n", __FUNCTION__, directDrawCreate, directDrawCreateEx);
HMODULE mod = NULL;
DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
2024-07-13 04:02:15 +02:00
HMODULE wndmode_dll = GetModuleHandleA("wndmode.dll");
2024-07-13 22:47:40 +02:00
if (wndmode_dll)
{
if ((getModuleHandleExA(flags, return_address, &mod) && mod == wndmode_dll) ||
(getModuleHandleExA(flags, directDrawCreate, &mod) && mod == wndmode_dll) ||
(getModuleHandleExA(flags, directDrawCreateEx, &mod) && mod == wndmode_dll))
2024-07-13 22:47:40 +02:00
{
MessageBoxA(
NULL,
"Error: You cannot combine cnc-ddraw with other DirectDraw wrappers. \n\n"
"Please remove/disable wndmode.dll and then try to start the game again.",
"Conflicting DirectDraw wrapper detected - cnc-ddraw",
MB_OK | MB_TOPMOST);
return TRUE;
}
}
2024-07-13 04:02:15 +02:00
HMODULE windmode_dll = GetModuleHandleA("windmode.dll");
2024-07-13 22:47:40 +02:00
if (windmode_dll)
{
if ((getModuleHandleExA(flags, return_address, &mod) && mod == windmode_dll) ||
(getModuleHandleExA(flags, directDrawCreate, &mod) && mod == windmode_dll) ||
(getModuleHandleExA(flags, directDrawCreateEx, &mod) && mod == windmode_dll))
2024-07-13 22:47:40 +02:00
{
MessageBoxA(
NULL,
"Error: You cannot combine cnc-ddraw with other DirectDraw wrappers. \n\n"
"Please remove/disable windmode.dll and then try to start the game again.",
"Conflicting DirectDraw wrapper detected - cnc-ddraw",
MB_OK | MB_TOPMOST);
return TRUE;
}
}
2024-07-13 04:02:15 +02:00
HMODULE dxwnd_dll = GetModuleHandleA("dxwnd.dll");
2024-07-13 22:47:40 +02:00
if (dxwnd_dll)
{
if ((getModuleHandleExA(flags, return_address, &mod) && mod == dxwnd_dll) ||
(getModuleHandleExA(flags, directDrawCreate, &mod) && mod == dxwnd_dll) ||
(getModuleHandleExA(flags, directDrawCreateEx, &mod) && mod == dxwnd_dll))
2024-07-13 22:47:40 +02:00
{
MessageBoxA(
NULL,
"Error: You cannot combine cnc-ddraw with other DirectDraw wrappers. \n\n"
"Please disable DxWnd and then try to start the game again.",
"Conflicting DirectDraw wrapper detected - cnc-ddraw",
MB_OK | MB_TOPMOST);
return TRUE;
}
}
2024-07-13 04:02:15 +02:00
HMODULE age_dll = GetModuleHandleA("age.dll");
2024-07-13 22:47:40 +02:00
if (age_dll)
{
if ((getModuleHandleExA(flags, return_address, &mod) && mod == age_dll) ||
(getModuleHandleExA(flags, directDrawCreate, &mod) && mod == age_dll) ||
(getModuleHandleExA(flags, directDrawCreateEx, &mod) && mod == age_dll))
2024-07-13 22:47:40 +02:00
{
MessageBoxA(
NULL,
"Error: You cannot combine cnc-ddraw with other DirectDraw wrappers. \n\n"
"Please disable the other wrapper by clicking in the game room on the very top \n"
"on 'Game', now select 'DirectX' and disable 'Render in 32-bit color'.",
"Conflicting DirectDraw wrapper detected - cnc-ddraw",
MB_OK | MB_TOPMOST);
return TRUE;
}
}
return FALSE;
}
BOOL util_is_bad_read_ptr(void* p)
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
if (VirtualQuery(p, &mbi, sizeof(mbi)))
{
DWORD mask = (
PAGE_READONLY |
PAGE_READWRITE |
PAGE_WRITECOPY |
PAGE_EXECUTE_READ |
PAGE_EXECUTE_READWRITE |
PAGE_EXECUTE_WRITECOPY);
BOOL b = !(mbi.Protect & mask);
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS))
b = TRUE;
2023-10-20 14:51:19 +02:00
return b;
}
return TRUE;
}
2023-08-20 23:12:00 +02:00
BOOL util_is_minimized(HWND hwnd)
{
RECT rc = { 0 };
return IsIconic(hwnd) || (real_GetClientRect(hwnd, &rc) && (rc.right - rc.left == 0 || rc.bottom - rc.top == 0));
}
BOOL util_in_foreground()
{
DWORD process_id = 0;
return GetWindowThreadProcessId(real_GetForegroundWindow(), &process_id) && process_id == GetCurrentProcessId();
}
2022-09-19 13:13:34 +02:00
BOOL util_is_avx_supported()
{
2022-09-22 19:28:35 +02:00
const DWORD XMM_STATE_BIT = 1 << 1;
const DWORD YMM_STATE_BIT = 1 << 2;
const DWORD OS_AVX_BITS = XMM_STATE_BIT | YMM_STATE_BIT;
const DWORD AVX_BIT = 1 << 28;
const DWORD OSXSAVE_BIT = 1 << 27;
const DWORD XSAVE_BIT = 1 << 26;
const DWORD CPU_AVX_BITS = AVX_BIT | OSXSAVE_BIT | XSAVE_BIT;
BOOL result = FALSE;
__try
{
2023-08-04 07:18:29 +02:00
int info[4] = { 0 };
__cpuid(info, 0);
2022-09-22 19:28:35 +02:00
2023-08-04 07:18:29 +02:00
if (info[0] >= 1)
2022-09-22 19:28:35 +02:00
{
2023-08-04 07:18:29 +02:00
__cpuid(info, 1);
if ((info[2] & CPU_AVX_BITS) == CPU_AVX_BITS)
{
unsigned int xcr0 = 0;
2022-09-19 13:13:34 +02:00
2022-09-22 20:27:56 +02:00
#ifdef _MSC_VER
2023-08-04 07:18:29 +02:00
xcr0 = (unsigned int)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
2022-09-22 20:27:56 +02:00
#elif __AVX__
2023-08-04 07:18:29 +02:00
__asm__("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx");
2022-09-19 13:13:34 +02:00
#endif
2023-08-04 07:18:29 +02:00
result = (xcr0 & OS_AVX_BITS) == OS_AVX_BITS;
}
2022-09-22 19:28:35 +02:00
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
2022-09-19 13:13:34 +02:00
2022-09-22 19:28:35 +02:00
return result;
2022-09-19 13:13:34 +02:00
}
2020-10-13 09:20:52 +02:00
void util_limit_game_ticks()
{
2024-03-22 22:27:00 +01:00
if (GetCurrentThreadId() != g_ddraw.gui_thread_id)
2022-10-19 23:48:20 +02:00
return;
2024-06-22 01:19:25 +02:00
/*
static void (WINAPI * getSystemTimePreciseAsFileTime)(LPFILETIME);
if (!getSystemTimePreciseAsFileTime)
{
getSystemTimePreciseAsFileTime = GetProcAddress(LoadLibraryA("Kernel32.dll"), "GetSystemTimePreciseAsFileTime");
//if (!getSystemTimePreciseAsFileTime)
// getSystemTimePreciseAsFileTime = GetSystemTimeAsFileTime;
}
if (1)
{
FILETIME ft = { 0 };
getSystemTimePreciseAsFileTime(&ft);
if (CompareFileTime((FILETIME*)&g_ddraw.ticks_limiter.due_time, &ft) == -1)
{
memcpy(&g_ddraw.ticks_limiter.due_time, &ft, sizeof(LARGE_INTEGER));
}
else
{
while (TRUE)
{
getSystemTimePreciseAsFileTime(&ft);
if (CompareFileTime((FILETIME*)&g_ddraw.ticks_limiter.due_time, &ft) <= 0)
break;
}
}
g_ddraw.ticks_limiter.due_time.QuadPart += g_ddraw.ticks_limiter.tick_length_ns;
}
else */
2024-03-22 22:27:00 +01:00
if (g_ddraw.ticks_limiter.htimer)
2020-10-13 09:20:52 +02:00
{
FILETIME ft = { 0 };
GetSystemTimeAsFileTime(&ft);
2024-03-22 22:27:00 +01:00
if (CompareFileTime((FILETIME*)&g_ddraw.ticks_limiter.due_time, &ft) == -1)
2020-10-13 09:20:52 +02:00
{
2024-03-22 22:27:00 +01:00
memcpy(&g_ddraw.ticks_limiter.due_time, &ft, sizeof(LARGE_INTEGER));
2020-10-13 09:20:52 +02:00
}
else
{
2024-03-22 22:27:00 +01:00
WaitForSingleObject(g_ddraw.ticks_limiter.htimer, g_ddraw.ticks_limiter.tick_length * 2);
2020-10-13 09:20:52 +02:00
}
2024-03-22 22:27:00 +01:00
g_ddraw.ticks_limiter.due_time.QuadPart += g_ddraw.ticks_limiter.tick_length_ns;
SetWaitableTimer(g_ddraw.ticks_limiter.htimer, &g_ddraw.ticks_limiter.due_time, 0, NULL, NULL, FALSE);
2020-10-13 09:20:52 +02:00
}
else
{
static DWORD next_game_tick;
2020-10-13 21:58:04 +02:00
2020-10-13 09:20:52 +02:00
if (!next_game_tick)
{
next_game_tick = timeGetTime();
return;
}
2020-10-13 21:58:04 +02:00
2024-03-22 22:27:00 +01:00
next_game_tick += g_ddraw.ticks_limiter.tick_length;
2020-10-13 09:20:52 +02:00
DWORD tick_count = timeGetTime();
int sleep_time = next_game_tick - tick_count;
2020-10-13 21:58:04 +02:00
2024-03-22 22:27:00 +01:00
if (sleep_time <= 0 || sleep_time > g_ddraw.ticks_limiter.tick_length)
2020-10-13 21:58:04 +02:00
{
2020-10-13 09:20:52 +02:00
next_game_tick = tick_count;
2020-10-13 21:58:04 +02:00
}
2020-10-13 09:20:52 +02:00
else
2020-10-13 21:58:04 +02:00
{
2020-10-13 09:20:52 +02:00
Sleep(sleep_time);
2020-10-13 21:58:04 +02:00
}
2020-10-13 09:20:52 +02:00
}
}
void util_update_bnet_pos(int new_x, int new_y)
{
static int old_x = -32000;
static int old_y = -32000;
2024-03-22 22:27:00 +01:00
if (old_x == -32000 || old_y == -32000 || !g_ddraw.bnet_active)
2020-10-13 09:20:52 +02:00
{
old_x = new_x;
old_y = new_y;
return;
}
POINT pt = { 0, 0 };
2024-03-22 22:27:00 +01:00
real_ClientToScreen(g_ddraw.hwnd, &pt);
2020-10-13 09:20:52 +02:00
RECT mainrc;
2024-03-22 22:27:00 +01:00
SetRect(&mainrc, pt.x, pt.y, pt.x + g_ddraw.width, pt.y + g_ddraw.height);
2020-10-13 09:20:52 +02:00
int adj_y = 0;
int adj_x = 0;
HWND hwnd = FindWindowEx(HWND_DESKTOP, NULL, "SDlgDialog", NULL);
while (hwnd != NULL)
{
RECT rc;
real_GetWindowRect(hwnd, &rc);
OffsetRect(&rc, new_x - old_x, new_y - old_y);
real_SetWindowPos(
hwnd,
0,
rc.left,
rc.top,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
2024-03-22 22:27:00 +01:00
if (rc.bottom - rc.top <= g_ddraw.height)
2020-10-13 09:20:52 +02:00
{
if (rc.bottom > mainrc.bottom && abs(mainrc.bottom - rc.bottom) > abs(adj_y))
2020-10-13 11:29:52 +02:00
{
2020-10-13 09:20:52 +02:00
adj_y = mainrc.bottom - rc.bottom;
2020-10-13 11:29:52 +02:00
}
2020-10-13 09:20:52 +02:00
else if (rc.top < mainrc.top && abs(mainrc.top - rc.top) > abs(adj_y))
2020-10-13 11:29:52 +02:00
{
2020-10-13 09:20:52 +02:00
adj_y = mainrc.top - rc.top;
2020-10-13 11:29:52 +02:00
}
2020-10-13 09:20:52 +02:00
}
2024-03-22 22:27:00 +01:00
if (rc.right - rc.left <= g_ddraw.width)
2020-10-13 09:20:52 +02:00
{
if (rc.right > mainrc.right && abs(mainrc.right - rc.right) > abs(adj_x))
2020-10-13 11:29:52 +02:00
{
2020-10-13 09:20:52 +02:00
adj_x = mainrc.right - rc.right;
2020-10-13 11:29:52 +02:00
}
2020-10-13 09:20:52 +02:00
else if (rc.left < mainrc.left && abs(mainrc.left - rc.left) > abs(adj_x))
2020-10-13 11:29:52 +02:00
{
2020-10-13 09:20:52 +02:00
adj_x = mainrc.left - rc.left;
2020-10-13 11:29:52 +02:00
}
2020-10-13 09:20:52 +02:00
}
hwnd = FindWindowEx(HWND_DESKTOP, hwnd, "SDlgDialog", NULL);
}
2021-06-11 20:30:43 +02:00
2020-10-13 09:20:52 +02:00
if (adj_x || adj_y)
{
HWND hwnd = FindWindowEx(HWND_DESKTOP, NULL, "SDlgDialog", NULL);
while (hwnd != NULL)
{
RECT rc;
real_GetWindowRect(hwnd, &rc);
OffsetRect(&rc, adj_x, adj_y);
real_SetWindowPos(
hwnd,
0,
rc.left,
rc.top,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
hwnd = FindWindowEx(HWND_DESKTOP, hwnd, "SDlgDialog", NULL);
}
}
old_x = new_x;
old_y = new_y;
}
2021-06-11 20:30:43 +02:00
BOOL util_get_lowest_resolution(
float ratio,
SIZE* out_res,
DWORD min_width,
DWORD min_height,
DWORD max_width,
DWORD max_height)
2020-10-13 09:20:52 +02:00
{
BOOL result = FALSE;
int org_ratio = (int)((ratio + 0.005f) * 100);
2020-10-13 09:20:52 +02:00
SIZE lowest = { .cx = max_width + 1, .cy = max_height + 1 };
DWORD i = 0;
DEVMODE m;
memset(&m, 0, sizeof(DEVMODE));
m.dmSize = sizeof(DEVMODE);
2024-06-10 00:05:04 +02:00
while (real_EnumDisplaySettingsA(NULL, i, &m))
2020-10-13 09:20:52 +02:00
{
2021-06-11 20:30:43 +02:00
if (m.dmPelsWidth >= min_width &&
2020-10-13 09:20:52 +02:00
m.dmPelsHeight >= min_height &&
m.dmPelsWidth <= max_width &&
m.dmPelsHeight <= max_height &&
2023-08-17 13:50:21 +02:00
m.dmPelsWidth <= lowest.cx &&
m.dmPelsHeight <= lowest.cy)
2020-10-13 09:20:52 +02:00
{
int res_ratio = (int)((((float)m.dmPelsWidth / m.dmPelsHeight) + 0.005f) * 100);
2020-10-13 09:20:52 +02:00
if (abs(res_ratio - org_ratio) <= 5)
2020-10-13 09:20:52 +02:00
{
result = TRUE;
out_res->cx = lowest.cx = m.dmPelsWidth;
out_res->cy = lowest.cy = m.dmPelsHeight;
}
}
2020-10-13 21:58:04 +02:00
2020-10-13 09:20:52 +02:00
memset(&m, 0, sizeof(DEVMODE));
m.dmSize = sizeof(DEVMODE);
i++;
}
return result;
}
2021-02-18 07:10:15 +01:00
void util_toggle_maximize()
{
RECT client_rc;
RECT dst_rc;
2021-02-18 07:10:15 +01:00
2024-03-22 22:27:00 +01:00
LONG style = real_GetWindowLongA(g_ddraw.hwnd, GWL_STYLE);
LONG exstyle = real_GetWindowLongA(g_ddraw.hwnd, GWL_EXSTYLE);
BOOL got_menu = GetMenu(g_ddraw.hwnd) != NULL;
2024-03-22 22:27:00 +01:00
if (real_GetClientRect(g_ddraw.hwnd, &client_rc) && SystemParametersInfo(SPI_GETWORKAREA, 0, &dst_rc, 0))
2021-02-18 07:10:15 +01:00
{
int width = (dst_rc.right - dst_rc.left);
int height = (dst_rc.bottom - dst_rc.top);
int x = dst_rc.left;
int y = dst_rc.top;
2024-03-22 22:27:00 +01:00
if (client_rc.right != g_ddraw.width || client_rc.bottom != g_ddraw.height)
2021-02-18 07:10:15 +01:00
{
dst_rc.left = 0;
dst_rc.top = 0;
2024-03-22 22:27:00 +01:00
dst_rc.right = g_ddraw.width;
dst_rc.bottom = g_ddraw.height;
AdjustWindowRectEx(&dst_rc, style, got_menu, exstyle);
}
2023-09-22 00:38:42 +02:00
else if (g_config.boxing)
{
dst_rc.left = 0;
dst_rc.top = 0;
2024-03-22 22:27:00 +01:00
dst_rc.right = g_ddraw.width;
dst_rc.bottom = g_ddraw.height;
for (int i = 20; i-- > 1;)
{
2024-03-22 22:27:00 +01:00
if (width >= g_ddraw.width * i && height - 20 >= g_ddraw.height * i)
{
2024-03-22 22:27:00 +01:00
dst_rc.right = g_ddraw.width * i;
dst_rc.bottom = g_ddraw.height * i;
break;
}
}
AdjustWindowRectEx(&dst_rc, style, got_menu, exstyle);
2021-02-18 07:10:15 +01:00
}
2023-09-22 00:38:42 +02:00
else if (g_config.maintas)
2021-02-18 07:10:15 +01:00
{
util_unadjust_window_rect(&dst_rc, style, got_menu, exstyle);
int w = dst_rc.right - dst_rc.left;
int h = dst_rc.bottom - dst_rc.top;
2024-03-22 22:27:00 +01:00
double dst_ar = (double)g_ddraw.height / g_ddraw.width;
2023-12-31 04:45:14 +01:00
double src_ar = (double)h / w;
dst_rc.top = 0;
dst_rc.left = 0;
dst_rc.right = w;
2023-12-31 04:45:14 +01:00
dst_rc.bottom = (LONG)round(dst_ar * w);
2023-12-31 04:45:14 +01:00
if (src_ar < dst_ar)
{
2023-12-31 04:35:08 +01:00
dst_rc.right = (LONG)round(((double)dst_rc.right / dst_rc.bottom) * h);
dst_rc.bottom = h;
}
AdjustWindowRectEx(&dst_rc, style, got_menu, exstyle);
2021-02-18 07:10:15 +01:00
}
RECT pos_rc;
pos_rc.left = (width / 2) - ((dst_rc.right - dst_rc.left) / 2) + x;
pos_rc.top = (height / 2) - ((dst_rc.bottom - dst_rc.top) / 2) + y;
pos_rc.right = (dst_rc.right - dst_rc.left);
pos_rc.bottom = (dst_rc.bottom - dst_rc.top);
util_unadjust_window_rect(&pos_rc, style, got_menu, exstyle);
util_unadjust_window_rect(&dst_rc, style, got_menu, exstyle);
util_set_window_rect(
pos_rc.left,
pos_rc.top,
dst_rc.right - dst_rc.left,
dst_rc.bottom - dst_rc.top,
0);
2021-02-18 07:10:15 +01:00
}
}
2020-10-13 09:20:52 +02:00
void util_toggle_fullscreen()
{
/* Disable ALT+ENTER on battle.net and Infantry Online Zone List Window */
2024-03-25 02:50:55 +01:00
if (g_ddraw.bnet_active || (g_config.infantryhack && GetMenu(g_ddraw.hwnd)))
2020-10-13 09:20:52 +02:00
return;
2023-09-22 00:38:42 +02:00
if (g_config.toggle_borderless && g_config.windowed)
2020-10-13 09:20:52 +02:00
{
2023-09-22 00:38:42 +02:00
if (!g_config.fullscreen)
2023-07-03 05:13:47 +02:00
{
mouse_unlock();
g_config.upscaled_state = g_config.fullscreen = TRUE;
2024-05-31 22:51:26 +02:00
dd_SetDisplayMode(0, 0, 0, 0);
2020-10-13 21:58:04 +02:00
2023-07-03 05:13:47 +02:00
mouse_lock();
}
else
{
mouse_unlock();
2020-10-13 21:58:04 +02:00
g_config.upscaled_state = g_config.fullscreen = FALSE;
2024-05-31 22:51:26 +02:00
dd_SetDisplayMode(0, 0, 0, 0);
2023-07-03 05:13:47 +02:00
//mouse_lock();
}
2020-10-13 09:20:52 +02:00
}
2023-07-03 05:13:47 +02:00
else
2020-10-13 09:20:52 +02:00
{
2023-09-22 00:38:42 +02:00
if (g_config.windowed)
2020-10-13 21:58:04 +02:00
{
2023-07-03 05:13:47 +02:00
mouse_unlock();
if (g_config.toggle_upscaled)
{
g_config.upscaled_state = g_config.fullscreen = TRUE;
}
2023-09-22 00:38:42 +02:00
g_config.window_state = g_config.windowed = FALSE;
2024-05-31 22:51:26 +02:00
dd_SetDisplayMode(0, 0, 0, SDM_LEAVE_WINDOWED);
2023-07-03 05:13:47 +02:00
util_update_bnet_pos(0, 0);
mouse_lock();
2020-10-13 21:58:04 +02:00
}
2020-10-13 09:20:52 +02:00
else
2020-10-13 21:58:04 +02:00
{
2023-07-03 05:13:47 +02:00
mouse_unlock();
if (g_config.toggle_upscaled)
{
g_config.upscaled_state = g_config.fullscreen = FALSE;
}
2023-09-22 00:38:42 +02:00
g_config.window_state = g_config.windowed = TRUE;
2020-10-13 09:20:52 +02:00
2024-03-22 22:27:00 +01:00
if (g_ddraw.renderer == d3d9_render_main && !g_config.nonexclusive)
2023-07-03 05:13:47 +02:00
{
2023-09-22 00:38:42 +02:00
d3d9_reset(g_config.windowed);
2023-07-03 05:13:47 +02:00
}
else
{
2024-03-22 22:27:00 +01:00
if (g_ddraw.render.thread)
{
2024-03-22 22:27:00 +01:00
EnterCriticalSection(&g_ddraw.cs);
g_ddraw.render.run = FALSE;
ReleaseSemaphore(g_ddraw.render.sem, 1, NULL);
LeaveCriticalSection(&g_ddraw.cs);
2024-03-22 22:27:00 +01:00
WaitForSingleObject(g_ddraw.render.thread, INFINITE);
g_ddraw.render.thread = NULL;
}
2024-03-22 22:27:00 +01:00
ChangeDisplaySettings(NULL, g_ddraw.bnet_active ? CDS_FULLSCREEN : 0);
2023-07-03 05:13:47 +02:00
}
2024-05-31 22:51:26 +02:00
dd_SetDisplayMode(0, 0, 0, SDM_LEAVE_FULLSCREEN);
2023-07-03 05:13:47 +02:00
//mouse_lock();
}
2020-10-13 09:20:52 +02:00
}
}
BOOL util_unadjust_window_rect(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle)
{
RECT rc;
SetRectEmpty(&rc);
BOOL fRc = AdjustWindowRectEx(&rc, dwStyle, fMenu, dwExStyle);
2020-10-13 21:58:04 +02:00
2020-10-13 09:20:52 +02:00
if (fRc)
{
prc->left -= rc.left;
prc->top -= rc.top;
prc->right -= rc.right;
prc->bottom -= rc.bottom;
}
return fRc;
}
void util_set_window_rect(int x, int y, int width, int height, UINT flags)
{
2023-09-22 00:38:42 +02:00
if (g_config.windowed)
2020-10-13 09:20:52 +02:00
{
2024-03-22 22:27:00 +01:00
if (g_ddraw.render.thread)
2020-10-13 09:20:52 +02:00
{
2024-03-22 22:27:00 +01:00
EnterCriticalSection(&g_ddraw.cs);
g_ddraw.render.run = FALSE;
ReleaseSemaphore(g_ddraw.render.sem, 1, NULL);
LeaveCriticalSection(&g_ddraw.cs);
2020-10-13 09:20:52 +02:00
2024-03-22 22:27:00 +01:00
WaitForSingleObject(g_ddraw.render.thread, INFINITE);
g_ddraw.render.thread = NULL;
2020-10-13 09:20:52 +02:00
}
if ((flags & SWP_NOMOVE) == 0)
{
g_config.window_rect.left = x;
g_config.window_rect.top = y;
}
if ((flags & SWP_NOSIZE) == 0)
{
g_config.window_rect.bottom = height;
g_config.window_rect.right = width;
}
2024-05-31 22:51:26 +02:00
dd_SetDisplayMode(0, 0, 0, 0);
2020-10-13 09:20:52 +02:00
}
}
BOOL CALLBACK util_enum_thread_wnd_proc(HWND hwnd, LPARAM lParam)
{
RECT size = { 0 };
real_GetClientRect(hwnd, &size);
2024-05-28 21:54:49 +02:00
LONG sytle = real_GetWindowLongA(hwnd, GWL_STYLE);
if (!g_ddraw.hwnd && !(sytle & WS_DISABLED) && size.right > 0 && size.bottom > 0)
g_ddraw.hwnd = hwnd;
2024-05-28 21:54:49 +02:00
#ifdef _DEBUG
char class[MAX_PATH] = { 0 };
GetClassNameA(hwnd, class, sizeof(class) - 1);
char title[MAX_PATH] = { 0 };
GetWindowTextA(hwnd, title, sizeof(title) - 1);
RECT pos = { 0 };
real_GetWindowRect(hwnd, &pos);
LONG exsytle = real_GetWindowLongA(hwnd, GWL_EXSTYLE);
TRACE(
"%s(class=%s, title=%s, X=%d, Y=%d, nWidth=%d, nHeight=%d)\n",
__FUNCTION__, class, title, pos.left, pos.top, size.right, size.bottom);
dbg_dump_wnd_styles(sytle, exsytle);
#endif
return TRUE;
}
2020-10-13 09:20:52 +02:00
BOOL CALLBACK util_enum_child_proc(HWND hwnd, LPARAM lparam)
{
IDirectDrawSurfaceImpl* this = (IDirectDrawSurfaceImpl*)lparam;
RECT size;
RECT pos;
2024-07-12 23:09:33 +02:00
if (real_GetClientRect(hwnd, &size) && real_GetWindowRect(hwnd, &pos))
2020-10-13 09:20:52 +02:00
{
2022-10-07 01:05:27 +02:00
char class_name[MAX_PATH] = { 0 };
GetClassNameA(hwnd, class_name, sizeof(class_name) - 1);
LONG exstyle = real_GetWindowLongA(hwnd, GWL_EXSTYLE);
2024-07-12 23:09:33 +02:00
HWND parent = GetParent(hwnd);
2022-10-07 01:05:27 +02:00
2024-06-04 21:54:05 +02:00
#ifdef _DEBUG_X
2024-07-12 23:09:33 +02:00
LONG style = real_GetWindowLongA(hwnd, GWL_STYLE);
2024-06-03 06:05:13 +02:00
2024-07-12 23:09:33 +02:00
TRACE("util_enum_child_proc class=%s, hwnd=%p, width=%u, height=%u, left=%d, top=%d, parent=%p, style=%08X\n",
class_name, hwnd, size.right, size.bottom, pos.left, pos.top, parent, style);
2024-06-04 21:54:05 +02:00
dbg_dump_wnd_styles(style, exstyle);
#endif
2024-06-04 03:40:29 +02:00
2024-07-12 23:09:33 +02:00
if (parent != g_ddraw.hwnd || size.right <= 1 || size.bottom <= 1 || strcmp(class_name, "Edit") == 0)
2024-06-04 03:40:29 +02:00
return TRUE;
if (g_config.fixchilds == FIX_CHILDS_DETECT_HIDE ||
2022-10-07 02:01:21 +02:00
strcmp(class_name, "VideoRenderer") == 0 ||
2024-06-06 02:30:12 +02:00
strcmp(class_name, "MCIQTZ_Window") == 0 ||
2024-02-17 23:18:42 +01:00
strcmp(class_name, "MCIAVI") == 0 ||
strcmp(class_name, "AVIWnd32") == 0 ||
strcmp(class_name, "MCIWndClass") == 0 ||
strcmp(class_name, "AVI Window") == 0)
{
2023-10-16 03:50:34 +02:00
if (g_config.fixchilds != FIX_CHILDS_DETECT_HIDE)
{
2024-03-22 22:27:00 +01:00
InterlockedExchangePointer((void*)&g_ddraw.video_window_hwnd, hwnd);
}
2021-05-22 12:23:25 +02:00
if (!(exstyle & WS_EX_TRANSPARENT))
{
real_SetWindowLongA(hwnd, GWL_EXSTYLE, exstyle | WS_EX_TRANSPARENT);
real_SetWindowPos(
hwnd,
0,
0,
0,
0,
0,
2023-09-26 06:54:12 +02:00
SWP_ASYNCWINDOWPOS | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
);
}
}
else if (!(exstyle & WS_EX_TRANSPARENT))
{
2024-03-22 22:27:00 +01:00
g_ddraw.got_child_windows = g_ddraw.child_window_exists = TRUE;
2020-10-13 09:20:52 +02:00
2023-09-22 00:38:42 +02:00
if (g_config.fixchilds == FIX_CHILDS_DETECT_PAINT)
{
HDC dst_dc = GetDC(hwnd);
HDC src_dc;
dds_GetDC(this, &src_dc);
2020-10-13 09:20:52 +02:00
2024-03-22 22:27:00 +01:00
real_MapWindowPoints(HWND_DESKTOP, g_ddraw.hwnd, (LPPOINT)&pos, 2);
2020-10-13 09:20:52 +02:00
2024-05-25 07:29:30 +02:00
real_BitBlt(dst_dc, 0, 0, size.right, size.bottom, src_dc, pos.left, pos.top, SRCCOPY);
ReleaseDC(hwnd, dst_dc);
}
}
2024-06-29 22:39:23 +02:00
2024-06-29 01:12:20 +02:00
if (strcmp(class_name, "TMediaPlayer") == 0)
return TRUE;
2020-10-13 09:20:52 +02:00
}
2024-06-04 21:54:05 +02:00
#ifdef _DEBUG_X
return TRUE;
#else
return FALSE;
2024-06-04 21:54:05 +02:00
#endif
2020-10-13 09:20:52 +02:00
}
static unsigned char util_get_pixel(int x, int y)
{
2021-06-11 20:30:43 +02:00
return ((unsigned char*)dds_GetBuffer(
2024-03-22 22:27:00 +01:00
g_ddraw.primary))[y * g_ddraw.primary->pitch + x * g_ddraw.primary->bytes_pp];
2020-10-13 09:20:52 +02:00
}
2021-05-15 02:58:07 +02:00
BOOL util_detect_low_res_screen()
2020-10-13 09:20:52 +02:00
{
/* struct Copied from wkReSolution */
typedef struct
{
PVOID UnkTable1;
DWORD Unk1, Unk2, Unk3, Unk4;
PVOID UnkDD, UnkTable2;
DWORD Unk5;
DWORD RenderWidth, RenderHeight;
DWORD Unk6, Unk7;
DWORD WidthRT, HeightRT;
DWORD HalfWidth, HalfHeight;
DWORD Unk8;
PCHAR UnkC;
LPDIRECTDRAW lpDD;
2024-05-10 00:03:14 +02:00
} * LPW2DDSTRUCT;
2020-10-13 09:20:52 +02:00
static int* in_movie = (int*)0x00665F58;
static int* is_vqa_640 = (int*)0x0065D7BC;
static BYTE* should_stretch = (BYTE*)0x00607D78;
static LPW2DDSTRUCT* pW2DS;
if (!pW2DS)
2024-05-08 07:10:35 +02:00
pW2DS = (LPW2DDSTRUCT*)((DWORD)GetModuleHandleA(NULL) + 0x799C4);
2020-10-13 09:20:52 +02:00
2024-03-22 22:27:00 +01:00
if (g_ddraw.width <= g_ddraw.upscale_hack_width || g_ddraw.height <= g_ddraw.upscale_hack_height)
2020-10-13 21:58:04 +02:00
{
2020-10-13 09:20:52 +02:00
return FALSE;
2020-10-13 21:58:04 +02:00
}
2020-10-13 09:20:52 +02:00
2024-03-22 22:27:00 +01:00
if (g_ddraw.isredalert)
2020-10-13 09:20:52 +02:00
{
if ((*in_movie && !*is_vqa_640) || *should_stretch)
{
return TRUE;
}
2020-10-13 21:58:04 +02:00
2020-10-13 09:20:52 +02:00
return FALSE;
}
2024-03-22 22:27:00 +01:00
else if (g_ddraw.iscnc1)
2020-10-13 09:20:52 +02:00
{
2021-06-11 20:30:43 +02:00
return
2024-03-22 22:27:00 +01:00
util_get_pixel(g_ddraw.upscale_hack_width + 1, 0) == 0 ||
util_get_pixel(g_ddraw.upscale_hack_width + 5, 1) == 0;
}
2024-03-22 22:27:00 +01:00
else if (g_ddraw.iskkndx)
{
2024-03-22 22:27:00 +01:00
return util_get_pixel(g_ddraw.width - 3, 3) == 0;
2020-10-13 09:20:52 +02:00
}
else if (g_ddraw.isworms2)
{
2024-05-08 09:04:19 +02:00
DWORD w2_width = *pW2DS ? (*pW2DS)->RenderWidth : 0;
DWORD w2_height = *pW2DS ? (*pW2DS)->RenderHeight : 0;
if (w2_width && w2_width < g_ddraw.width && w2_height && w2_height < g_ddraw.height)
{
2024-05-08 09:04:19 +02:00
if (g_ddraw.upscale_hack_width != w2_width || g_ddraw.upscale_hack_height != w2_height)
{
2024-05-08 09:04:19 +02:00
g_ddraw.upscale_hack_width = w2_width;
g_ddraw.upscale_hack_height = w2_height;
InterlockedExchange(&g_ddraw.upscale_hack_active, FALSE);
}
return TRUE;
}
}
2020-10-13 09:20:52 +02:00
return FALSE;
}