Skip to content
This repository has been archived by the owner on Sep 29, 2024. It is now read-only.

Commit

Permalink
fix surf buffer size on max resolution with windowed mode
Browse files Browse the repository at this point in the history
added window observer thread
  • Loading branch information
DiaLight committed Dec 25, 2022
1 parent 7f4a8f5 commit 17feeaa
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 31 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ set(SOURCES
patches/screen_resolution/patch_draw_buffer_extra_size.cpp
patches/screen_resolution/replace_custom_heap.cpp
patches/screen_resolution/dpi_aware.cpp
patches/screen_resolution/fix_surface_buffer_size_on_max_resolution.cpp
reimpl/SurfHashList__probablySort.cpp
reimpl/draw3dScene.cpp
stdex.cpp
Expand Down
17 changes: 17 additions & 0 deletions api/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <api.h>
#include <api/window.h>
#include <dk2/window.h>
#include <dk2.h>

namespace api {

Expand All @@ -25,8 +26,24 @@ namespace api {
return lResult;
}

std::vector <std::function<BOOL(dk2::MyGame *game, int &dwWidth, int &dwHeight, int &dwRGBBitCount, int &isWindowed, int &a6, int &a7)>> BEFORE_PREPARE_SCREEN;
int g_width = 0;
int g_height = 0;

// handling __thiscall though __fastcall
// __thiscall: ecx, esp[0], esp[1], esp[2], ...
// __fastcall: ecx, edx, esp[0], esp[1], ...
int __fastcall proxy_prepareScreen(dk2::MyGame *this_, void *edx, int dwWidth, int dwHeight, int dwRGBBitCount, int isWindowed, int a6, int a7) {
g_width = dwWidth;
g_height = dwHeight;
printf("prepareScreen %p %dx%d %d %d %d %d\n", this_, dwWidth, dwHeight, dwRGBBitCount, isWindowed, a6, a7);
for(auto &F : BEFORE_PREPARE_SCREEN) if(!F(this_, dwWidth, dwHeight, dwRGBBitCount, isWindowed, a6, a7)) return FALSE;
return this_->prepareScreen(dwWidth, dwHeight, dwRGBBitCount, isWindowed, a6, a7);
}

bool initWindow() {
if(!replaceXrefs(funptr<&dk2::CWindowTest::proc>(), proxy_proc)) return false;
if(!replaceXrefs(funptr<&dk2::MyGame::prepareScreen>(), proxy_prepareScreen)) return false;
return true;
}

Expand Down
7 changes: 7 additions & 0 deletions include/api/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@
#ifndef EMBER_WINDOW_H
#define EMBER_WINDOW_H

namespace dk2 {
class MyGame;
}
namespace api {

extern std::vector <std::function<bool(HWND & , UINT & , WPARAM & , LPARAM & )>> BEFORE_WINDOW_PROC;
extern std::vector <std::function<void(HWND, UINT, WPARAM, LPARAM, LRESULT & )>> AFTER_WINDOW_PROC;

extern std::vector <std::function<BOOL(dk2::MyGame *game, int &dwWidth, int &dwHeight, int &dwRGBBitCount, int &isWindowed, int &a6, int &a7)>> BEFORE_PREPARE_SCREEN;
extern int g_width;
extern int g_height;

bool initWindow();

}
Expand Down
1 change: 1 addition & 0 deletions include/patches.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace patch {
bool expand_surf_idx_array();
bool expand_surf_hash_list();
bool patch_draw_buffer_extra_size();
bool fix_surface_buffer_size_on_max_resolution();
bool replace_custom_heap();
bool dpi_aware();

Expand Down
38 changes: 38 additions & 0 deletions launcher/launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@ bool enumModes(HWND hWnd, std::vector<screen_mode> &list) {
return true;
}

struct CollectWindows {
DWORD procId = 0;
DWORD count = 0;
};

BOOL CALLBACK CollectWindows_WndEnumProc(HWND hWnd, LPARAM lParam) {
CollectWindows &collect = *(CollectWindows *) lParam;
DWORD procId = 0;
GetWindowThreadProcessId(hWnd, &procId);
if(collect.procId == procId) {
DWORD dwStyle = GetWindowStyle(hWnd);
if((dwStyle & WS_VISIBLE) != 0) {
collect.count++;
}
}
return TRUE;
}

bool CreateProcess_runAndWait(const wchar_t *cmd, const wchar_t *dir, DWORD &lastError, DWORD &exitCode) {
SECURITY_ATTRIBUTES saAttr;
Expand Down Expand Up @@ -289,6 +306,26 @@ bool CreateProcess_runAndWait(const wchar_t *cmd, const wchar_t *dir, DWORD &las
return false;
}

std::thread thr([&pi] { // window observer thread
while(WaitForSingleObject(pi.hProcess, 2000) == WAIT_TIMEOUT) {
CollectWindows collect;
std::stringstream ss;
collect.procId = pi.dwProcessId;
EnumWindows(CollectWindows_WndEnumProc, (LPARAM) &collect);
if(collect.count != 0) continue;
if(WaitForSingleObject(pi.hProcess, 2000) != WAIT_TIMEOUT) break;
collect.count = 0;
EnumWindows(CollectWindows_WndEnumProc, (LPARAM) &collect);
if(collect.count != 0) continue;
int iStatus = MessageBoxA(NULL,
"Running process without open windows detected\n"
"terminate DK2 process?",
"DK2 window observer thread", MB_OKCANCEL);
if(iStatus == IDOK) {
TerminateProcess(pi.hProcess, 1);
}
}
});
#define BUFSIZE 4096
DWORD dwRead;
std::string line;
Expand Down Expand Up @@ -317,6 +354,7 @@ bool CreateProcess_runAndWait(const wchar_t *cmd, const wchar_t *dir, DWORD &las
CloseHandle(hChildStd_OUT_Rd);

WaitForSingleObject(pi.hProcess, INFINITE);
thr.join();
GetExitCodeProcess(pi.hProcess, &exitCode);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Expand Down
1 change: 1 addition & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extern "C" __declspec(dllexport) bool __cdecl ember_initialize() {
if(!patch::expand_surf_idx_array()) return false;
if(!patch::expand_surf_hash_list()) return false;
if(!patch::patch_draw_buffer_extra_size()) return false;
if(!patch::fix_surface_buffer_size_on_max_resolution()) return false;
if(!patch::replace_custom_heap()) return false;
if(!patch::dpi_aware()) return false;

Expand Down
19 changes: 5 additions & 14 deletions patches/control_windowed_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,16 @@
#include <patches.h>
#include <cstdio>

namespace {
bool isFullscreen;
}
// handling __thiscall though __fastcall
// __thiscall: ecx, esp[0], esp[1], esp[2], ...
// __fastcall: ecx, edx, esp[0], esp[1], ...
int __fastcall proxy_prepareScreen(dk2::MyGame *this_, void *edx, int dwWidth, int dwHeight, int dwRGBBitCount, int isWindowed, int a6, int a7) {
printf("prepareScreen %p %dx%d %d %d %d %d\n", this_, dwWidth, dwHeight, dwRGBBitCount, isWindowed, a6, a7);
// call __thiscall
return this_->prepareScreen(dwWidth, dwHeight, dwRGBBitCount, !isFullscreen, a6, a7);
}

bool patch::control_windowed_mode() {
std::string arg = api::findArgValue("fullscreen");
if(arg.empty()) return true;
if(arg != "false" && arg != "true") return false;
isFullscreen = arg == "true";
bool isFullscreen = arg == "true";
printf("use fullscreen: %s\n", arg.c_str());
if(!replaceXrefs(funptr<&dk2::MyGame::prepareScreen>(), proxy_prepareScreen)) return false;
api::BEFORE_PREPARE_SCREEN.push_back([isFullscreen](dk2::MyGame *game, int &dwWidth, int &dwHeight, int &dwRGBBitCount, int &isWindowed, int &a6, int &a7) {
isWindowed = !isFullscreen;
return TRUE;
});
return true;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Created by DiaLight on 25.12.2022.
//
#include <patches.h>
#include <api/patch.h>
#include <api.h>

typedef BOOL (WINAPI *GetClientRect_t)(HWND hWnd, LPRECT lpRect);
BOOL WINAPI reimpl_GetClientRect(HWND hWnd, LPRECT lpRect) {
BOOL ret = GetClientRect(hWnd, lpRect);
int width = lpRect->right - lpRect->left;
int height = lpRect->bottom - lpRect->top;
if(width != api::g_width || height != api::g_height) {
printf("FIX: GetClientRect: l=%d, t=%d, r=%d, b=%d => create surf %dx%d but game expect to work with buffers %dx%d\n",
lpRect->left, lpRect->top, lpRect->right, lpRect->bottom,
width, height,
api::g_width, api::g_height
);
lpRect->right = lpRect->left + api::g_width;
lpRect->bottom = lpRect->top + api::g_height;
}
return ret;
}
GetClientRect_t pGetClientRect = reimpl_GetClientRect;

bool patch::fix_surface_buffer_size_on_max_resolution() {
// .text:00556077 mov ebp, ds:GetClientRect
GetClientRect_t **ppGetClientRect = (GetClientRect_t **) (dk2_base + (0x00556077 + 2 - dk2_virtual_base));
DWORD oldProtect;
if(!VirtualProtect(ppGetClientRect, sizeof(uint32_t), PAGE_EXECUTE_READWRITE, &oldProtect)) return false;
*ppGetClientRect = &pGetClientRect;
VirtualProtect(ppGetClientRect, sizeof(uint32_t), oldProtect, NULL);
return true;
}
17 changes: 0 additions & 17 deletions patches/screen_resolution/patch_draw_buffer_extra_size.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,10 @@ void *__cdecl reimpl_mydd_alloc_buf2(int width, int height) {
return mydd_alloc_buf2(width + 16, height + 58);
}

typedef BOOL (WINAPI *GetClientRect_t)(HWND hWnd, LPRECT lpRect);
BOOL WINAPI reimpl_GetClientRect(HWND hWnd, LPRECT lpRect) {
BOOL ret = GetClientRect(hWnd, lpRect);
// BOOL ret = GetWindowRect(hWnd, lpRect);
// lpRect->right += 50;
// lpRect->bottom += 50;
return ret;
}
GetClientRect_t pGetClientRect = reimpl_GetClientRect;

bool patch::patch_draw_buffer_extra_size() {
mydd_alloc_buf = (mydd_alloc_buf_t) (dk2_base + (0x005A7980 - dk2_virtual_base));
mydd_alloc_buf2 = (mydd_alloc_buf_t) (dk2_base + (0x005A79C0 - dk2_virtual_base));
if(!replaceXrefs((uint8_t *) mydd_alloc_buf, reimpl_mydd_alloc_buf)) return false;
if(!replaceXrefs((uint8_t *) mydd_alloc_buf2, reimpl_mydd_alloc_buf2)) return false;

// .text:00556077 mov ebp, ds:GetClientRect
GetClientRect_t **ppGetClientRect = (GetClientRect_t **) (dk2_base + (0x00556077 + 2 - dk2_virtual_base));
DWORD oldProtect;
if(!VirtualProtect(ppGetClientRect, sizeof(uint32_t), PAGE_EXECUTE_READWRITE, &oldProtect)) return false;
*ppGetClientRect = &pGetClientRect;
VirtualProtect(ppGetClientRect, sizeof(uint32_t), oldProtect, NULL);
return true;
}

0 comments on commit 17feeaa

Please sign in to comment.