Skip to content

Commit abed24c

Browse files
committed
better background window ensure sequence
1 parent 50bae04 commit abed24c

File tree

1 file changed

+175
-106
lines changed

1 file changed

+175
-106
lines changed

EmperorHooks/dllmain.cpp

Lines changed: 175 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include "PatchDebugLog.hpp"
1515
#include "PatchSettings.hpp"
1616
#include "PatchLan.hpp"
17+
#include <string_view>
18+
#include <winternl.h>
19+
#include <Ntstatus.h>
1720

1821

1922
int (WINAPI* TrueShowCursor)(BOOL bShow) = ShowCursor;
@@ -55,7 +58,6 @@ void setupConsole()
5558
}
5659
}
5760

58-
bool isBorderlessWindowed = true;
5961

6062
volatile HWND backgroundWindowHandle = nullptr;
6163
volatile DWORD backgroundWindowThreadId = 0;
@@ -72,113 +74,27 @@ typedef BOOL(__cdecl* SetWindowStyleAndDrainMessagesFuncType)(HWND hWnd, int wid
7274
SetWindowStyleAndDrainMessagesFuncType setWindowStyleAndDrainMessagesOriginal = (SetWindowStyleAndDrainMessagesFuncType)0x004A7260;
7375
BOOL __cdecl setWindowStyleAndDrainMessages(HWND hWnd, int width, int height, char windowedMode)
7476
{
75-
DWORD style; // ebp
76-
int useWidth; // esi
77-
int useHeight; // ebx
78-
BOOL hasWindow; // esi
79-
DWORD extendedStyle; // eax
80-
BOOL result; // eax
81-
struct tagRECT rc; // [esp+10h] [ebp-2Ch] BYREF
82-
struct tagMSG Msg; // [esp+20h] [ebp-1Ch] BYREF
83-
84-
style = WS_POPUP;
85-
useWidth = GetSystemMetrics(SM_CXSCREEN);
86-
useHeight = GetSystemMetrics(SM_CYSCREEN);
87-
if (windowedMode)
88-
{
89-
useWidth = width;
90-
useHeight = height;
91-
if (!isBorderlessWindowed)
92-
style = WS_POPUPWINDOW | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_DLGFRAME;
93-
}
94-
SetWindowLongA(hWnd, GWL_STYLE, style);
95-
if (isBorderlessWindowed)
96-
{
97-
int left = GetSystemMetrics(SM_CXSCREEN) / 2 - useWidth / 2;
98-
SetWindowPos(hWnd, HWND_TOPMOST, left, 0, useWidth, useHeight, SWP_SHOWWINDOW);
77+
SetWindowLongA(hWnd, GWL_STYLE, WS_POPUP);
78+
int left = GetSystemMetrics(SM_CXSCREEN) / 2 - width / 2;
79+
SetWindowPos(hWnd, HWND_TOPMOST, left, 0, width, height, SWP_SHOWWINDOW);
9980

100-
RECT rc = {};
101-
GetWindowRect(*mainWindowHandleP, &rc);
102-
myClipCursor(&rc);
103-
}
104-
else
105-
{
106-
SetRect(&rc, 0, 0, useWidth, useHeight);
107-
hasWindow = GetMenu(hWnd) != 0;
108-
extendedStyle = GetWindowLongA(hWnd, GWL_EXSTYLE);
109-
AdjustWindowRectEx(&rc, style, hasWindow, extendedStyle);
110-
MoveWindow(hWnd, 0, 0, rc.right - rc.left, rc.bottom - rc.top, 0);
111-
ShowWindow(hWnd, SW_SHOW);
112-
InvalidateRect(hWnd, 0, 0);
113-
}
81+
RECT rc = {};
82+
GetWindowRect(*mainWindowHandleP, &rc);
83+
myClipCursor(&rc);
11484

115-
for (result = PeekMessageA(&Msg, 0, 0, 0, 0); result; result = PeekMessageA(&Msg, 0, 0, 0, 0))
85+
BOOL result;
86+
MSG msg;
87+
for (result = PeekMessageA(&msg, 0, 0, 0, 0); result; result = PeekMessageA(&msg, 0, 0, 0, 0))
11688
{
117-
GetMessageA(&Msg, 0, 0, 0);
118-
if (Msg.message == WM_QUIT && (Msg.hwnd == *mainWindowHandleP || (HWND)Msg.wParam == *mainWindowHandleP))
89+
GetMessageA(&msg, 0, 0, 0);
90+
if (msg.message == WM_QUIT && (msg.hwnd == *mainWindowHandleP || (HWND)msg.wParam == *mainWindowHandleP))
11991
*gDoQuitP = 1;
120-
TranslateMessage(&Msg);
121-
DispatchMessageA(&Msg);
92+
TranslateMessage(&msg);
93+
DispatchMessageA(&msg);
12294
}
12395
return result;
12496
}
12597

126-
typedef int(__stdcall* WndProcDuneIIIType)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
127-
WndProcDuneIIIType wndProcDuneIIIOriginal = (WndProcDuneIIIType)0x004A6560;
128-
129-
130-
int __stdcall wndProcDuneIII(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
131-
{
132-
int ret = wndProcDuneIIIOriginal(hWnd, Msg, wParam, lParam);
133-
134-
135-
if (hWnd == *mainWindowHandleP && Msg == WM_ACTIVATEAPP)
136-
{
137-
if (wParam || (!wParam && lParam == backgroundWindowThreadId))
138-
{
139-
printf("GAINED FOCUS\n");
140-
focus = true;
141-
}
142-
else
143-
{
144-
printf("LOST FOCUS\n");
145-
focus = false;
146-
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
147-
ShowWindow(hWnd, SW_MINIMIZE);
148-
149-
SetWindowPos(backgroundWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
150-
ShowWindow(backgroundWindowHandle, SW_MINIMIZE);
151-
}
152-
}
153-
154-
static bool hadFocus = true;
155-
156-
if (focus && !hadFocus)
157-
{
158-
RECT rc = {};
159-
GetWindowRect(*mainWindowHandleP, &rc);
160-
myClipCursor(&rc);
161-
162-
std::thread([]()
163-
{
164-
printf("%p %p\n", *mainWindowHandleP, backgroundWindowHandle);
165-
Sleep(1000 * 2);
166-
ShowWindow(backgroundWindowHandle, SW_SHOWNOACTIVATE);
167-
Sleep(1000 * 2);
168-
SetWindowPos(backgroundWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
169-
Sleep(1000 * 2);
170-
SetWindowPos(*mainWindowHandleP, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
171-
ShowWindow(*mainWindowHandleP, SW_SHOW);
172-
}).detach();
173-
}
174-
175-
hadFocus = focus;
176-
177-
return ret;
178-
}
179-
180-
181-
18298
void backgroundWindow()
18399
{
184100
backgroundWindowThreadId = GetCurrentThreadId();
@@ -232,6 +148,163 @@ void backgroundWindow()
232148
}
233149
}
234150

151+
struct SYSTEM_PROCESS_ID_INFORMATION
152+
{
153+
HANDLE ProcessId;
154+
UNICODE_STRING ImageName;
155+
};
156+
157+
constexpr SYSTEM_INFORMATION_CLASS SystemProcessIdInformation = SYSTEM_INFORMATION_CLASS(0x58);
158+
159+
NTSTATUS GetProcessPathById(DWORD ProcessId, wchar_t** output)
160+
{
161+
NTSTATUS status = S_OK;
162+
163+
HMODULE ntdll = nullptr;
164+
NTSTATUS(*NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength) = nullptr;
165+
166+
SYSTEM_PROCESS_ID_INFORMATION spii = { (HANDLE)ProcessId, { .Length = 0, .MaximumLength = 4096, .Buffer = nullptr } };
167+
168+
169+
ntdll = LoadLibraryA("ntdll.dll");
170+
if (!ntdll)
171+
{
172+
status = GetLastError();
173+
goto error;
174+
}
175+
176+
NtQuerySystemInformation = (NTSTATUS (*)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength))GetProcAddress(ntdll, "NtQuerySystemInformation");
177+
if (!NtQuerySystemInformation)
178+
{
179+
status = GetLastError();
180+
goto error;
181+
}
182+
183+
spii.ImageName.Buffer = (PWSTR)LocalAlloc(LMEM_FIXED, spii.ImageName.MaximumLength);
184+
if (!spii.ImageName.Buffer)
185+
{
186+
status = GetLastError();
187+
goto error;
188+
}
189+
190+
status = NtQuerySystemInformation(SystemProcessIdInformation, &spii, sizeof(spii), 0);
191+
if (status == STATUS_INFO_LENGTH_MISMATCH)
192+
{
193+
LocalFree(spii.ImageName.Buffer);
194+
spii.ImageName.Buffer = (PWSTR)LocalAlloc(LMEM_FIXED, spii.ImageName.MaximumLength);
195+
if (!spii.ImageName.Buffer)
196+
{
197+
status = GetLastError();
198+
goto error;
199+
}
200+
}
201+
202+
if (status != S_OK)
203+
goto error;
204+
205+
*output = spii.ImageName.Buffer;
206+
goto end;
207+
208+
error:
209+
if (spii.ImageName.Buffer)
210+
LocalFree(spii.ImageName.Buffer);
211+
212+
end:
213+
if (ntdll)
214+
FreeLibrary(ntdll);
215+
216+
return status;
217+
}
218+
219+
void windowSwitchHandlerLoop()
220+
{
221+
while (!*mainWindowHandleP || !backgroundWindow)
222+
Sleep(10);
223+
224+
HWND lastForeground = nullptr;
225+
bool force = true;
226+
227+
228+
while (true)
229+
{
230+
Sleep(1000);
231+
232+
HWND foreground = GetForegroundWindow();
233+
234+
DWORD dwProcId = 0;
235+
if (!GetWindowThreadProcessId(foreground, &dwProcId))
236+
{
237+
printf("GetWindowThreadProcessId failed %d\n", GetLastError());
238+
}
239+
else
240+
{
241+
wchar_t* processPath = nullptr;
242+
NTSTATUS status = GetProcessPathById(dwProcId, &processPath);
243+
if (status != S_OK)
244+
{
245+
printf("GetProcessPathById failed %d\n", status);
246+
}
247+
else
248+
{
249+
//printf("fg %d %d %S !!!\n", DWORD(foreground), dwProcId, processPath);
250+
251+
// sometimes during loading dwm.exe / WerFault.exe take over as the "Game.exe is not responding" window
252+
bool isDwmExe = std::wstring_view(processPath).ends_with(L"\\dwm.exe");
253+
bool isWerFaultExe = std::wstring_view(processPath).ends_with(L"\\WerFault.exe");
254+
255+
LocalFree(processPath);
256+
257+
if (isDwmExe || isWerFaultExe)
258+
continue;
259+
}
260+
}
261+
262+
if (foreground == backgroundWindowHandle)
263+
{
264+
printf("bg was fg, fixing\n");
265+
ShowWindow(*mainWindowHandleP, SW_SHOW);
266+
SetForegroundWindow(*mainWindowHandleP);
267+
lastForeground = *mainWindowHandleP;
268+
Sleep(1000 * 3);
269+
continue;
270+
}
271+
else if ((foreground == *mainWindowHandleP && lastForeground != *mainWindowHandleP) || force)
272+
{
273+
printf("SHOW START\n");
274+
275+
printf(" topmost bg\n");
276+
SetWindowPos(backgroundWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
277+
printf(" show bg\n");
278+
ShowWindow(backgroundWindowHandle, SW_SHOWMAXIMIZED);
279+
SetForegroundWindow(backgroundWindowHandle);
280+
281+
//Sleep(1000 * 3);
282+
283+
printf(" topmost main\n");
284+
SetWindowPos(*mainWindowHandleP, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
285+
printf(" show main\n");
286+
ShowWindow(*mainWindowHandleP, SW_SHOW);
287+
SetForegroundWindow(*mainWindowHandleP);
288+
289+
//Sleep(1000 * 3);
290+
291+
printf("SHOW DONE\n");
292+
force = false;
293+
}
294+
else if (foreground != *mainWindowHandleP && lastForeground == *mainWindowHandleP)
295+
{
296+
printf("HIDE\n");
297+
SetWindowPos(*mainWindowHandleP, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
298+
ShowWindow(*mainWindowHandleP, SW_MINIMIZE);
299+
300+
SetWindowPos(backgroundWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
301+
ShowWindow(backgroundWindowHandle, SW_MINIMIZE);
302+
}
303+
304+
lastForeground = foreground;
305+
}
306+
}
307+
235308
__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
236309
{
237310
if (DetourIsHelperProcess()) {
@@ -240,9 +313,6 @@ __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOI
240313

241314
if (dwReason == DLL_PROCESS_ATTACH)
242315
{
243-
MessageBoxA(nullptr, "AAA", "AAA", 0);
244-
245-
246316
DWORD doFullscreen = 1;
247317
DWORD size = sizeof(DWORD);
248318
HRESULT result = RegGetValueA(HKEY_CURRENT_USER, "Software\\WestwoodRedirect\\Emperor\\LauncherCustomSettings", "DoFullscreen", RRF_RT_REG_DWORD, nullptr, &doFullscreen, &size);
@@ -259,10 +329,8 @@ __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOI
259329
DetourAttach(&(PVOID&)OutputDebugStringWReal, OutputDebugStringWWrap);
260330
//DetourAttach(&(PVOID&)TrueShowCursor, FakeShowCursor);
261331
if (doFullscreen)
262-
{
263332
DetourAttach(&(PVOID&)setWindowStyleAndDrainMessagesOriginal, setWindowStyleAndDrainMessages);
264-
DetourAttach(&(PVOID&)wndProcDuneIIIOriginal, wndProcDuneIII);
265-
}
333+
266334
DetourAttach(&(PVOID&)doCdCheckOrig, doCdCheckPatched);
267335
DetourAttach(&(PVOID&)regSettingsOpenHkeyOrig, regSettingsOpenHkeyPatched);
268336
HookD3D7();
@@ -275,6 +343,7 @@ __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOI
275343
if (doFullscreen)
276344
{
277345
std::thread([]() { backgroundWindow(); }).detach();
346+
std::thread([]() { windowSwitchHandlerLoop(); }).detach();
278347
std::thread([]()
279348
{
280349
while (true)

0 commit comments

Comments
 (0)