Game Development Community

Alt-Tab Crash

by Alex Stone · in Torque Game Engine · 04/21/2008 (10:21 am) · 30 replies

**SEE THREE POSTS DOWN FOR FIX**

Game crashes on Windows Vista and Windows XP when you alt-tab out and then back into a game while it is full-screen and using the OpenGL render driver. This is confirmed happening with an unmodified distro of the Torque SDK.

I checked with GG staff and they believe the problem may have to do with mode switching.

Stack Trace (note my line numbers may by slightly different than yours):


First-chance exception at 0x6bda834f in torqueDemo_DEBUG.exe: 0xC0000005: Access violation reading location 0x6bda834f.

Unhandled exception at 0x6bda834f in torqueDemo_DEBUG.exe: 0xC0000005: Access violation reading location 0x6bda834f.



user32.dll!GetMessageW() + 0x6e bytes

user32.dll!GetMessageW() + 0x146 bytes

user32.dll!GetMessageW() + 0x261 bytes

user32.dll!OffsetRect() + 0x4d bytes

ntdll.dll!KiUserCallbackDispatcher() + 0x2e bytes

user32.dll!MsgWaitForMultipleObjectsEx() + 0xc5 bytes

> > torqueDemo_DEBUG.exe!ProcessMessages() Line 912 + 0x14 bytes C++

torqueDemo_DEBUG.exe!Platform::process() Line 935 + 0x5 bytes C++

torqueDemo_DEBUG.exe!DemoGame::main(int argc=1, const char * * argv=0x001c2148) Line 451 C++

torqueDemo_DEBUG.exe!run(int argc=1, const char * * argv=0x001c2148) Line 1398 + 0x1c bytes C++

torqueDemo_DEBUG.exe!main(int argc=1, const char * * argv=0x001c2148) Line 1467 + 0xd bytes C++

torqueDemo_DEBUG.exe!__tmainCRTStartup() Line 327 + 0x19 bytes C

torqueDemo_DEBUG.exe!mainCRTStartup() Line 196 C

kernel32.dll!BaseThreadInitThunk() + 0x12 bytes

ntdll.dll!LdrInitializeThunk() + 0x4d bytes



This crash occurs on a variety of WinXP/Vista machines with different rendering hardware Including Nvidia and ATI.

How to replicate on your copy:

Run torqueDemo.exe.

Open the options dialog.

Check the Fullscreen box.

Click apply.

Wait for everything to reload.

Press Alt-Tab.

Press Alt-Tab again OR click on the game window in the Task Bar.
Page «Previous 1 2
#1
04/21/2008 (10:43 am)
Just thought I would post the code that helped others with this case from Amanda Fitch's programming team. These changes were to WinWindow.CC in the function WindowProc in the WM_ACTIVATEAPP case. It did not help in Alex's case, so any help people can give would be very much appreciated!

case WM_ACTIVATEAPP:

         if ((bool) wParam)

         {

            Video::reactivate();

            ShowCursor(false);

            if ( Video::isFullScreen() )

               hideTheTaskbar();

 

            // HACK:  Windows 98 (after switching from fullscreen to windowed mode)

            SetForegroundWindow( winState.appWindow );

 

            // If our keyboard state is dirty, clear it

            if( sgKeyboardStateDirty == true )

            {

               sgKeyboardStateDirty = false;

               InitInput();

            }

 

            // Your code may not need this... it was simply a way to inform the script that we were restarting audio!

            Con::executef( 2, "playBGM", 0 );

         }

         else

         {

            // Window lost focus so set a dirty flag on the keyboard state

            if ( lParam == 0 )

               sgKeyboardStateDirty = true;

 

            Video::deactivate();

            restoreTheTaskbar();

 

            alxStopAll();

 

         }

         break;
#2
04/26/2008 (10:45 am)
**SEE NEXT POST FOR FIX**

I actually got a more complete and accurate stack trace:

663f834f()
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb3 bytes
user32.dll!_DispatchClientMessage@20() + 0x4b bytes
user32.dll!___fnDWORD@4() + 0x24 bytes
ntdll.dll!_KiUserCallbackDispatcher@12() + 0x2e bytes
user32.dll!_NtUserPeekMessage@20() + 0xc bytes
user32.dll!__PeekMessage@24() + 0x2d bytes
user32.dll!_PeekMessageW@20() + 0x179 bytes
torque.exe!ProcessMessages() Line 994 + 0x16 bytes C++
torque.exe!Platform::process() Line 1022 + 0x5 bytes C++
> torque.exe!DemoGame::main(int argc=4, const char * * argv=0x01f31a50) Line 478 C++
torque.exe!main(int argc=4, const char * * argv=0x01f31a50) Line 1604 + 0x2e bytes C++
torque.exe!__tmainCRTStartup() Line 266 + 0x12 bytes C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes

It looks like somehow the window context is getting stale. Could it be because it's processing message during destroying and recreating the window?
#3
04/26/2008 (3:55 pm)
Yeah, so I totally fixed this. The problem turned out to be a fundamental flaw in the way torque processes WM_ACTIVATEAPP messages. Torque destroys and recreates the window when processing this message, while still in the message loop, which could easily cause the Win32 API to freak out. The solution is to move the actual work of reactivating the game into the next trip through Platform::process, outside the messaging loop.

Part 1: Setting up some extra Video tracking state

In platformVideo.h, after

static bool smCritical;

insert

static bool smActive;
   static bool smActivating;
   static bool smReactivating;
   static bool smInactive;

after

static void setVideo(const char * gapi, const char * vendor, const char * renderer, const char * platform, const char * os, const char * arch);

insert

static bool isActive() { return smActive; }
   static bool isActivating() { return smActivating; }
   static bool isReactivating() { return smReactivating; }
   static bool isInactive() { return smInactive; }

In platformVideo.cc, after

bool					Video::smCritical = false;
bool					Video::smNeedResurrect = false;

insert

bool                    Video::smActive = false;
bool                    Video::smActivating = false;
bool                    Video::smReactivating = false;
bool                    Video::smInactive = false;

In Video::setDevice, after

Con::printf( "Activating the %s display device...", renderName );
      smCurrentDevice = smDeviceList[deviceIndex];

      smCritical = true;

insert

smActivating = true;

and after

bool result = smCurrentDevice->activate( width, height, bpp, fullScreen );

insert

smActivating = false;
	  smActive = true;
	  smInactive = false;

In Video::deactivate, after

Platform::minimizeWindow();
      smCritical = false;
   }

insert

smInactive = true;
   smActive = false;

in Video::reactivate, after

Resolution res = DisplayDevice::getResolution();

      smCritical = true;

insert

smReactivating = true;

and after

smCurrentDevice->activate(res.w,res.h,res.bpp,DisplayDevice::isFullScreen());

insert

smReactivating = false;
	  smInactive = false;
	  smActive = true;

Ok, now for Part Deux, rearranging the reactivation code in winWindow.cc:

After:

static bool gWindowCreated = false;

static bool windowNotActive = false;

Insert:

static bool gDoReactivate = false;

In Platform::process, after:

void Platform::process()
{

Insert:

if(gDoReactivate)
   {
            Video::reactivate();
            ShowCursor(false);
            if ( Video::isFullScreen() )
               hideTheTaskbar();

            // HACK:  Windows 98 (after switching from fullscreen to windowed mode)
            SetForegroundWindow( winState.appWindow );

            // If our keyboard state is dirty, clear it
            if( sgKeyboardStateDirty == true )
            {
               sgKeyboardStateDirty = false;
               InitInput();
            }

			gDoReactivate = false;
   }

In WindowProc, after

case WM_ACTIVATEAPP:
         if ((bool) wParam)
         {

REPLACE THE CODE UP TO THE CLOSURE OF THE IF STATEMENT WITH:

if(Video::isInactive() && !Video::isReactivating())
			 {
				gDoReactivate = true;
			 }

So it should look like...

case WM_ACTIVATEAPP:
         if ((bool) wParam)
         {
			 //>NEW CODE
			 if(Video::isInactive() && !Video::isReactivating())
			 {
				gDoReactivate = true;
			 }
			 //<NEW CODE
         }

NOTE: THIS IS A TENTATIVE FIX, it has not been tested on any other platforms except my own machine, but it no longer crashes when you alt-tab back into the game while it is in fullscreen. I'm actually a little suprised that GG didn't catch this in their QA process, as it seems to be a hardware independant bug in the windows platform code.
#4
04/27/2008 (11:17 am)
Extremely cool and helpful! I'll make sure that people get this to test!
#5
04/27/2008 (9:44 pm)
Solved my Alt-Tab problems. (My crash occurred only when going from Full-screen to Windowed Mode). This needs to be a resource.
#6
05/17/2008 (4:50 am)
This worked for me as well! No more nasty crashes.

And here is a little change I made to make it minimize the game window when you alt-tab out of full screen mode(or else all you will see is the task bar as the game window will stay on top of everything else):

After
case WM_ACTIVATEAPP:
   if ((bool) wParam)
   {
      if(Video::isInactive() && !Video::isReactivating())
      {
         gDoReactivate = true;
      }
   }
which was added by the changes above, add
else if(Video::isFullScreen())
      Platform::minimizeWindow();
so that the case block looks like:
case WM_ACTIVATEAPP:
   if ((bool) wParam)
   {
      if(Video::isInactive() && !Video::isReactivating())
      {
         gDoReactivate = true;
      }
   }
   else if(Video::isFullScreen())
      Platform::minimizeWindow();
   break;
#7
05/21/2008 (12:27 pm)
Very good Nelson!
#8
06/04/2008 (12:19 pm)
Would that work for tgb 1.7.2?
I'm having the same problem too.
#9
06/04/2008 (12:21 pm)
People have been using it.
#10
06/05/2008 (8:37 am)
I've tried it yesterday and it does work :)
Thanks guys , you rock!
BTW I've noticed that when you alt tab from full screen into windows , the resolution maintain its game resolution(800*600) and only when completely quit the game it switch back to my default res.
Anyway... it's way better than crash.
#11
06/22/2008 (7:23 am)
I am using TGE 1.4 and inside Platform::process() it is giving me an error saying that sgKeyboardStateDirty is an undeclared identifier. Is this a different name in 1.4?

Well I figured out a way to just simply disable Alt-Tab altogether.

inside WindowProc
right above the switch ( message ) call just add:
#define MY_HOTKEYID 100
bool isMyKeyComboTrapped = RegisterHotKey(hWnd, MY_HOTKEYID, MOD_ALT, VK_TAB);
#12
06/26/2008 (4:12 pm)
Anyone running the shader water enhancement seeing a crash when the window is restored? It looks like the shader data is trashed when the window is destroyed. I tried calling initShader() when the window is restored, but I am still seeing a crash. This is after the alt-tab fix.
#13
07/31/2008 (7:04 am)
I added this to TGE 1.5.2 and it works the first time I tab out and back into the game. But the second time I try to tab out the game doesn't minimize or anything. I still have an active game window. Any thoughts?
#14
07/31/2008 (7:09 am)
Ahhh ok I have to click in the game window when I tab out and back in before I can tab out again. Is there a way to make the widow active so you don't have to click on the screen before you can tab out again?
#15
01/04/2009 (9:57 pm)
I'm now getting the same error on 1.7.4
I was hoping that by now it would be implemented into TGB, but I guess we need to redo it for every torque version.
#16
01/07/2009 (8:02 pm)
I believe this was proposed post-code freeze for 1.7.4.
#17
01/07/2009 (8:25 pm)
Totaly understand. I'm just glad it works.
I've made the same changes on 1.7.4 and it's solid again. took me 5 min.
This is actually a big deal for anyone who is planing on publishing the game. I couldn't passed the portals QA before I fixed it.
And there is no way I could have come up with this fix myself so this post is gold!
#18
01/08/2009 (7:31 am)
@Eyal,

Glad to hear you have fixed it. I have the same problem here... so I want to ask what the fix is? Can you share the fix for other people having the same problem?

Thanks

Isaac
#19
01/08/2009 (7:43 am)
So the Alex Stone post is the current fix?
#20
01/08/2009 (7:50 am)
Yes, the 4th post is the one I've used. ( Posted: Apr 26, 2008 14:55 )
Thank Alex. I just copyied his work ;)
Page «Previous 1 2