From e0ff30aeacb5cfb1817045eb29451099bc33331a Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 11 May 2025 23:01:32 +0200 Subject: [PATCH 1/2] [GEN][ZH] Fix ALT+Tab crash --- .../W3DDevice/GameClient/W3DDisplay.cpp | 28 ------------------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 6 ++++ .../Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 3 +- Generals/Code/Main/WinMain.cpp | 14 ++++++---- .../W3DDevice/GameClient/W3DDisplay.cpp | 28 ------------------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 6 ++++ .../Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 3 +- GeneralsMD/Code/Main/WinMain.cpp | 14 ++++++---- 8 files changed, 34 insertions(+), 68 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index a9905aeac7..373a42f8df 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -489,34 +489,6 @@ void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false); } -/*Giant hack in order to keep the game from getting stuck when alt-tabbing*/ -void Reset_D3D_Device(bool active) -{ - if (TheDisplay && WW3D::Is_Initted() && !TheDisplay->getWindowed()) - { - if (active) - { - //switch back to desired mode when user alt-tabs back into game - WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true); - OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); - if (GetVersionEx(&osvi)) - { //check if we're running Win9x variant since they have buggy alt-tab that requires - //reloading all textures. - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - { //only do this on Win9x boxes because it makes alt-tab very slow. - WW3D::_Invalidate_Textures(); - } - } - } - else - { - //switch to windowed mode whenever the user alt-tabs out of game. Don't restore assets after reset since we'll do it when returning. - WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true, false); - } - } -} - /** Set resolution of display */ //============================================================================= Bool W3DDisplay::setDisplayMode( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed ) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 684bf2e42d..a0cb18850a 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1028,7 +1028,10 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int bool ret; if (reset_device) + { + WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.\n")); ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. + } else ret = Create_Device(); @@ -1100,6 +1103,7 @@ void DX8Wrapper::Set_Swap_Interval(int swap) default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; } + WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.\n")); Reset_Device(); } @@ -1169,6 +1173,7 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe Resize_And_Position_Window(); } #pragma message("TODO: support changing windowed status and changing the bit depth") + WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.\n")); return Reset_Device(); } else { return false; @@ -1604,6 +1609,7 @@ void DX8Wrapper::End_Scene(bool flip_frames) if (hr==D3DERR_DEVICELOST) { hr=_Get_D3D_Device8()->TestCooperativeLevel(); if (hr==D3DERR_DEVICENOTRESET) { + WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.\n")); Reset_Device(); } else { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 003268ad80..e142159f6f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -817,7 +817,8 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f // Check if the device needs to be reset if( D3DERR_DEVICENOTRESET == hr ) { - DX8Wrapper::Reset_Device(); + WWDEBUG_SAY(("WW3D::Begin_Render is resetting the device.\n")); + DX8Wrapper::Reset_Device(); } return WW3D_ERROR_GENERIC; diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index a6b023be24..ce3b441d88 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -87,8 +87,6 @@ const char *gAppPrefix = ""; /// So WB can have a different debug log file name. #define DEFAULT_XRESOLUTION 800 #define DEFAULT_YRESOLUTION 600 -extern void Reset_D3D_Device(bool active); - static Bool gInitializing = false; static Bool gDoPaint = true; static Bool isWinMainActive = false; @@ -426,14 +424,20 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, //------------------------------------------------------------------------- case WM_ACTIVATEAPP: { -// DWORD threadId=GetCurrentThreadId(); if ((bool) wParam != isWinMainActive) - { isWinMainActive = (BOOL) wParam; + { + // TheSuperHackers @bugfix xezon 11/05/2025 This event originally called DX8Wrapper::Reset_Device, + // intended to clear resources on a lost device in fullscreen, but effectively also in + // windowed mode, if the DXMaximizedWindowedMode shim was applied in newer versions of Windows, + // which lead to unfortunate application crashing. Resetting the device on WM_ACTIVATEAPP instead + // of TestCooperativeLevel() == D3DERR_DEVICENOTRESET is not a requirement. There are other code + // paths that take care of that. + + isWinMainActive = (BOOL) wParam; if (TheGameEngine) TheGameEngine->setIsActive(isWinMainActive); - Reset_D3D_Device(isWinMainActive); if (isWinMainActive) { //restore mouse cursor to our custom version. if (TheWin32Mouse) diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 7b5a8bddc7..96c21103ad 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -555,34 +555,6 @@ void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false); } -/*Giant hack in order to keep the game from getting stuck when alt-tabbing*/ -void Reset_D3D_Device(bool active) -{ - if (TheDisplay && WW3D::Is_Initted() && !TheDisplay->getWindowed()) - { - if (active) - { - //switch back to desired mode when user alt-tabs back into game - WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true); - OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); - if (GetVersionEx(&osvi)) - { //check if we're running Win9x variant since they have buggy alt-tab that requires - //reloading all textures. - if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - { //only do this on Win9x boxes because it makes alt-tab very slow. - WW3D::_Invalidate_Textures(); - } - } - } - else - { - //switch to windowed mode whenever the user alt-tabs out of game. Don't restore assets after reset since we'll do it when returning. - WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true, false); - } - } -} - /** Set resolution of display */ //============================================================================= Bool W3DDisplay::setDisplayMode( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed ) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index d67fc9ef32..2bf210615d 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1118,7 +1118,10 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int bool ret; if (reset_device) + { + WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.\n")); ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. + } else ret = Create_Device(); @@ -1190,6 +1193,7 @@ void DX8Wrapper::Set_Swap_Interval(int swap) default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; } + WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.\n")); Reset_Device(); } @@ -1259,6 +1263,7 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe Resize_And_Position_Window(); } #pragma message("TODO: support changing windowed status and changing the bit depth") + WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.\n")); return Reset_Device(); } else { return false; @@ -1749,6 +1754,7 @@ void DX8Wrapper::End_Scene(bool flip_frames) if (hr==D3DERR_DEVICELOST) { hr=_Get_D3D_Device8()->TestCooperativeLevel(); if (hr==D3DERR_DEVICENOTRESET) { + WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.\n")); Reset_Device(); } else { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 9eecf04432..936201c84b 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -810,7 +810,8 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f // Check if the device needs to be reset if( D3DERR_DEVICENOTRESET == hr ) { - DX8Wrapper::Reset_Device(); + WWDEBUG_SAY(("WW3D::Begin_Render is resetting the device.\n")); + DX8Wrapper::Reset_Device(); } return WW3D_ERROR_GENERIC; diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index b365a7ec9a..9a538fc7fe 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -90,8 +90,6 @@ const char *gAppPrefix = ""; /// So WB can have a different debug log file name. #define DEFAULT_XRESOLUTION 800 #define DEFAULT_YRESOLUTION 600 -extern void Reset_D3D_Device(bool active); - static Bool gInitializing = false; static Bool gDoPaint = true; static Bool isWinMainActive = false; @@ -448,14 +446,20 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, //------------------------------------------------------------------------- case WM_ACTIVATEAPP: { -// DWORD threadId=GetCurrentThreadId(); if ((bool) wParam != isWinMainActive) - { isWinMainActive = (BOOL) wParam; + { + // TheSuperHackers @bugfix xezon 11/05/2025 This event originally called DX8Wrapper::Reset_Device, + // intended to clear resources on a lost device in fullscreen, but effectively also in + // windowed mode, if the DXMaximizedWindowedMode shim was applied in newer versions of Windows, + // which lead to unfortunate application crashing. Resetting the device on WM_ACTIVATEAPP instead + // of TestCooperativeLevel() == D3DERR_DEVICENOTRESET is not a requirement. There are other code + // paths that take care of that. + + isWinMainActive = (BOOL) wParam; if (TheGameEngine) TheGameEngine->setIsActive(isWinMainActive); - Reset_D3D_Device(isWinMainActive); if (isWinMainActive) { //restore mouse cursor to our custom version. if (TheWin32Mouse) From 4df53541bb5a70d65618f102988a34dd88a1add1 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 19 May 2025 21:50:10 +0200 Subject: [PATCH 2/2] Revert loggings --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 6 ------ Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 3 +-- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 6 ------ GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 3 +-- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a0cb18850a..684bf2e42d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1028,10 +1028,7 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int bool ret; if (reset_device) - { - WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.\n")); ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. - } else ret = Create_Device(); @@ -1103,7 +1100,6 @@ void DX8Wrapper::Set_Swap_Interval(int swap) default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; } - WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.\n")); Reset_Device(); } @@ -1173,7 +1169,6 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe Resize_And_Position_Window(); } #pragma message("TODO: support changing windowed status and changing the bit depth") - WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.\n")); return Reset_Device(); } else { return false; @@ -1609,7 +1604,6 @@ void DX8Wrapper::End_Scene(bool flip_frames) if (hr==D3DERR_DEVICELOST) { hr=_Get_D3D_Device8()->TestCooperativeLevel(); if (hr==D3DERR_DEVICENOTRESET) { - WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.\n")); Reset_Device(); } else { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index e142159f6f..003268ad80 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -817,8 +817,7 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f // Check if the device needs to be reset if( D3DERR_DEVICENOTRESET == hr ) { - WWDEBUG_SAY(("WW3D::Begin_Render is resetting the device.\n")); - DX8Wrapper::Reset_Device(); + DX8Wrapper::Reset_Device(); } return WW3D_ERROR_GENERIC; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 2bf210615d..d67fc9ef32 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1118,10 +1118,7 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int bool ret; if (reset_device) - { - WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.\n")); ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. - } else ret = Create_Device(); @@ -1193,7 +1190,6 @@ void DX8Wrapper::Set_Swap_Interval(int swap) default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; } - WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.\n")); Reset_Device(); } @@ -1263,7 +1259,6 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe Resize_And_Position_Window(); } #pragma message("TODO: support changing windowed status and changing the bit depth") - WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.\n")); return Reset_Device(); } else { return false; @@ -1754,7 +1749,6 @@ void DX8Wrapper::End_Scene(bool flip_frames) if (hr==D3DERR_DEVICELOST) { hr=_Get_D3D_Device8()->TestCooperativeLevel(); if (hr==D3DERR_DEVICENOTRESET) { - WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.\n")); Reset_Device(); } else { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 936201c84b..9eecf04432 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -810,8 +810,7 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f // Check if the device needs to be reset if( D3DERR_DEVICENOTRESET == hr ) { - WWDEBUG_SAY(("WW3D::Begin_Render is resetting the device.\n")); - DX8Wrapper::Reset_Device(); + DX8Wrapper::Reset_Device(); } return WW3D_ERROR_GENERIC;