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
1922int (WINAPI* TrueShowCursor)(BOOL bShow) = ShowCursor;
@@ -55,7 +58,6 @@ void setupConsole()
5558 }
5659}
5760
58- bool isBorderlessWindowed = true ;
5961
6062volatile HWND backgroundWindowHandle = nullptr ;
6163volatile DWORD backgroundWindowThreadId = 0 ;
@@ -72,113 +74,27 @@ typedef BOOL(__cdecl* SetWindowStyleAndDrainMessagesFuncType)(HWND hWnd, int wid
7274SetWindowStyleAndDrainMessagesFuncType setWindowStyleAndDrainMessagesOriginal = (SetWindowStyleAndDrainMessagesFuncType)0x004A7260 ;
7375BOOL __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-
18298void 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