Skip to content

Commit e0ff30a

Browse files
committed
[GEN][ZH] Fix ALT+Tab crash
1 parent be0f696 commit e0ff30a

File tree

8 files changed

+34
-68
lines changed

8 files changed

+34
-68
lines changed

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -489,34 +489,6 @@ void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate
489489
DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false);
490490
}
491491

492-
/*Giant hack in order to keep the game from getting stuck when alt-tabbing*/
493-
void Reset_D3D_Device(bool active)
494-
{
495-
if (TheDisplay && WW3D::Is_Initted() && !TheDisplay->getWindowed())
496-
{
497-
if (active)
498-
{
499-
//switch back to desired mode when user alt-tabs back into game
500-
WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true);
501-
OSVERSIONINFO osvi;
502-
osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
503-
if (GetVersionEx(&osvi))
504-
{ //check if we're running Win9x variant since they have buggy alt-tab that requires
505-
//reloading all textures.
506-
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
507-
{ //only do this on Win9x boxes because it makes alt-tab very slow.
508-
WW3D::_Invalidate_Textures();
509-
}
510-
}
511-
}
512-
else
513-
{
514-
//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.
515-
WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true, false);
516-
}
517-
}
518-
}
519-
520492
/** Set resolution of display */
521493
//=============================================================================
522494
Bool W3DDisplay::setDisplayMode( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed )

Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,10 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int
10281028
bool ret;
10291029

10301030
if (reset_device)
1031+
{
1032+
WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.\n"));
10311033
ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app.
1034+
}
10321035
else
10331036
ret = Create_Device();
10341037

@@ -1100,6 +1103,7 @@ void DX8Wrapper::Set_Swap_Interval(int swap)
11001103
default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break;
11011104
}
11021105

1106+
WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.\n"));
11031107
Reset_Device();
11041108
}
11051109

@@ -1169,6 +1173,7 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe
11691173
Resize_And_Position_Window();
11701174
}
11711175
#pragma message("TODO: support changing windowed status and changing the bit depth")
1176+
WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.\n"));
11721177
return Reset_Device();
11731178
} else {
11741179
return false;
@@ -1604,6 +1609,7 @@ void DX8Wrapper::End_Scene(bool flip_frames)
16041609
if (hr==D3DERR_DEVICELOST) {
16051610
hr=_Get_D3D_Device8()->TestCooperativeLevel();
16061611
if (hr==D3DERR_DEVICENOTRESET) {
1612+
WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.\n"));
16071613
Reset_Device();
16081614
}
16091615
else {

Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,8 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f
817817
// Check if the device needs to be reset
818818
if( D3DERR_DEVICENOTRESET == hr )
819819
{
820-
DX8Wrapper::Reset_Device();
820+
WWDEBUG_SAY(("WW3D::Begin_Render is resetting the device.\n"));
821+
DX8Wrapper::Reset_Device();
821822
}
822823

823824
return WW3D_ERROR_GENERIC;

Generals/Code/Main/WinMain.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,6 @@ const char *gAppPrefix = ""; /// So WB can have a different debug log file name.
8787
#define DEFAULT_XRESOLUTION 800
8888
#define DEFAULT_YRESOLUTION 600
8989

90-
extern void Reset_D3D_Device(bool active);
91-
9290
static Bool gInitializing = false;
9391
static Bool gDoPaint = true;
9492
static Bool isWinMainActive = false;
@@ -426,14 +424,20 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
426424
//-------------------------------------------------------------------------
427425
case WM_ACTIVATEAPP:
428426
{
429-
// DWORD threadId=GetCurrentThreadId();
430427
if ((bool) wParam != isWinMainActive)
431-
{ isWinMainActive = (BOOL) wParam;
428+
{
429+
// TheSuperHackers @bugfix xezon 11/05/2025 This event originally called DX8Wrapper::Reset_Device,
430+
// intended to clear resources on a lost device in fullscreen, but effectively also in
431+
// windowed mode, if the DXMaximizedWindowedMode shim was applied in newer versions of Windows,
432+
// which lead to unfortunate application crashing. Resetting the device on WM_ACTIVATEAPP instead
433+
// of TestCooperativeLevel() == D3DERR_DEVICENOTRESET is not a requirement. There are other code
434+
// paths that take care of that.
435+
436+
isWinMainActive = (BOOL) wParam;
432437

433438
if (TheGameEngine)
434439
TheGameEngine->setIsActive(isWinMainActive);
435440

436-
Reset_D3D_Device(isWinMainActive);
437441
if (isWinMainActive)
438442
{ //restore mouse cursor to our custom version.
439443
if (TheWin32Mouse)

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -555,34 +555,6 @@ void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate
555555
DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false);
556556
}
557557

558-
/*Giant hack in order to keep the game from getting stuck when alt-tabbing*/
559-
void Reset_D3D_Device(bool active)
560-
{
561-
if (TheDisplay && WW3D::Is_Initted() && !TheDisplay->getWindowed())
562-
{
563-
if (active)
564-
{
565-
//switch back to desired mode when user alt-tabs back into game
566-
WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true);
567-
OSVERSIONINFO osvi;
568-
osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
569-
if (GetVersionEx(&osvi))
570-
{ //check if we're running Win9x variant since they have buggy alt-tab that requires
571-
//reloading all textures.
572-
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
573-
{ //only do this on Win9x boxes because it makes alt-tab very slow.
574-
WW3D::_Invalidate_Textures();
575-
}
576-
}
577-
}
578-
else
579-
{
580-
//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.
581-
WW3D::Set_Render_Device( WW3D::Get_Render_Device(),TheDisplay->getWidth(),TheDisplay->getHeight(),TheDisplay->getBitDepth(),TheDisplay->getWindowed(),true, true, false);
582-
}
583-
}
584-
}
585-
586558
/** Set resolution of display */
587559
//=============================================================================
588560
Bool W3DDisplay::setDisplayMode( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed )

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,10 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int
11181118
bool ret;
11191119

11201120
if (reset_device)
1121+
{
1122+
WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.\n"));
11211123
ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app.
1124+
}
11221125
else
11231126
ret = Create_Device();
11241127

@@ -1190,6 +1193,7 @@ void DX8Wrapper::Set_Swap_Interval(int swap)
11901193
default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break;
11911194
}
11921195

1196+
WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.\n"));
11931197
Reset_Device();
11941198
}
11951199

@@ -1259,6 +1263,7 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe
12591263
Resize_And_Position_Window();
12601264
}
12611265
#pragma message("TODO: support changing windowed status and changing the bit depth")
1266+
WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.\n"));
12621267
return Reset_Device();
12631268
} else {
12641269
return false;
@@ -1749,6 +1754,7 @@ void DX8Wrapper::End_Scene(bool flip_frames)
17491754
if (hr==D3DERR_DEVICELOST) {
17501755
hr=_Get_D3D_Device8()->TestCooperativeLevel();
17511756
if (hr==D3DERR_DEVICENOTRESET) {
1757+
WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.\n"));
17521758
Reset_Device();
17531759
}
17541760
else {

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,8 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f
810810
// Check if the device needs to be reset
811811
if( D3DERR_DEVICENOTRESET == hr )
812812
{
813-
DX8Wrapper::Reset_Device();
813+
WWDEBUG_SAY(("WW3D::Begin_Render is resetting the device.\n"));
814+
DX8Wrapper::Reset_Device();
814815
}
815816

816817
return WW3D_ERROR_GENERIC;

GeneralsMD/Code/Main/WinMain.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ const char *gAppPrefix = ""; /// So WB can have a different debug log file name.
9090
#define DEFAULT_XRESOLUTION 800
9191
#define DEFAULT_YRESOLUTION 600
9292

93-
extern void Reset_D3D_Device(bool active);
94-
9593
static Bool gInitializing = false;
9694
static Bool gDoPaint = true;
9795
static Bool isWinMainActive = false;
@@ -448,14 +446,20 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message,
448446
//-------------------------------------------------------------------------
449447
case WM_ACTIVATEAPP:
450448
{
451-
// DWORD threadId=GetCurrentThreadId();
452449
if ((bool) wParam != isWinMainActive)
453-
{ isWinMainActive = (BOOL) wParam;
450+
{
451+
// TheSuperHackers @bugfix xezon 11/05/2025 This event originally called DX8Wrapper::Reset_Device,
452+
// intended to clear resources on a lost device in fullscreen, but effectively also in
453+
// windowed mode, if the DXMaximizedWindowedMode shim was applied in newer versions of Windows,
454+
// which lead to unfortunate application crashing. Resetting the device on WM_ACTIVATEAPP instead
455+
// of TestCooperativeLevel() == D3DERR_DEVICENOTRESET is not a requirement. There are other code
456+
// paths that take care of that.
457+
458+
isWinMainActive = (BOOL) wParam;
454459

455460
if (TheGameEngine)
456461
TheGameEngine->setIsActive(isWinMainActive);
457462

458-
Reset_D3D_Device(isWinMainActive);
459463
if (isWinMainActive)
460464
{ //restore mouse cursor to our custom version.
461465
if (TheWin32Mouse)

0 commit comments

Comments
 (0)