Runtime Error in Vista

Archives Forums/Blitz3D Bug Reports/Runtime Error in Vista

Knotz(Posted 2007) [#1]
The following situation does result in a runtime error:

code:
Graphics3D 640,480 

SetBuffer BackBuffer() 

camera=CreateCamera() 
light=CreateLight() 

cone=CreateCone( 32 ) 
PositionEntity cone,0,0,5 

While Not KeyDown( 1 ) 
RenderWorld 
Flip 
Wend 

End 


1) Run the program above.
2) Open a program that needs administrator rights.
3) The screen dims ( Vista wants a confirmation )
4) The program crashes with a runtime error.

I don't think it's a major issue but still worth noting.

Knotz.


Gillissie(Posted 2007) [#2]
I would say it's a major issue, since that is essentially the most basic 3D program you can write with Blitz3D. I am very nervous about the future of our favorite language.


DGuy(Posted 2007) [#3]
This issue stems from the cause of many of the MAV's I've encounted while working with B3D. Which is that, when running in windowed mode, B3D assumes it will never lose the DirectDraw surfaces being used.

In fullscreen mode, when focus is lost then re-gained, B3D will restore DirectDraw surfaces, but in windowed mode no surface restoring is done.

I worked around this issue by making use of an external DLL (written in C++), that receives the address of the DirectDraw object (obtained via SystemProperty) used by B3D, enumerating all DD Surfaces until the primary surface is found, storing the address of the primary surface, then checking each time through the main loop if the primary surface has been lost. If it has been lost, I do a RestoreAllSurfaces, reload all my graphics and continue running.

The C++ code for this amounts to about a dozen lines and it works on both WinXP and Vista.

HTH,
DGuy


markcw(Posted 2007) [#4]
DGuy, could you show us the c++ source of your dll if you don't mind? It would be appreciated.


DGuy(Posted 2007) [#5]
Here goes the relevant parts of the DLL:

// Blitz3D ====================================================================
//-----------------------------------------------------------------------------
.lib "B3D_AppBase.dll"
app_DDHook%(pDD7%):"_app_DDHook@4"
app_DDUnHook():"_app_DDUnHook@0"
app_DDWasLost%():"_app_DDWasLost@0"


// C++ ========================================================================
//-----------------------------------------------------------------------------
#include <windows.h>
#define DIRECTDRAW_VERSION 0x0700
#include <ddraw.h>


//-----------------------------------------------------------------------------
#define BBDECL extern "C" _declspec(dllexport)
#define BBCALL _stdcall


//-----------------------------------------------------------------------------
static LPDIRECTDRAW7        _b3d_pdd;      // pointer to DirectDraw object
static LPDIRECTDRAWSURFACE7 _b3d_pddsPrim; // pointer to primary DirectDraw surface


//-----------------------------------------------------------------------------
BOOL APIENTRY DllMain( HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/ )
 {
 switch( ul_reason_for_call )
  {
  case DLL_PROCESS_ATTACH: break;
  case DLL_THREAD_ATTACH: break;
  case DLL_THREAD_DETACH: break;
  case DLL_PROCESS_DETACH: break;
  }
 return TRUE;
 }


//-----------------------------------------------------------------------------
// called by 'app_DDHook()'
HRESULT WINAPI _surfaceEnumCallback_GetPrimary( LPDIRECTDRAWSURFACE7 lpDDSurface, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID /*lpContext*/ )
 {
 if( lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE )
  {
  _b3d_pddsPrim = lpDDSurface;
  return DDENUMRET_CANCEL;
  }
 lpDDSurface->Release();
 return DDENUMRET_OK;
 }


//-----------------------------------------------------------------------------
// Should be called after B3D graphics mode has been set
BBDECL BOOL BBCALL app_DDHook( LPDIRECTDRAW7 pDD )
 {
 if( pDD )
  {
  _b3d_pdd = pDD;
  return (DD_OK == _b3d_pdd->EnumSurfaces( DDENUMSURFACES_DOESEXIST | DDENUMSURFACES_ALL, NULL, NULL, _surfaceEnumCallback_GetPrimary ));
  }
 return FALSE;
 }


//-----------------------------------------------------------------------------
// Should be called before B3D graphics mode is cleared
BBDECL void BBCALL app_DDUnHook()
 {
 if( _b3d_pddsPrim )
  {
  _b3d_pddsPrim->Release();
  _b3d_pddsPrim = NULL;
  _b3d_pdd = NULL;
  }
 }


//-----------------------------------------------------------------------------
// Should be called each time through Blitz3D main-loop
BBDECL BOOL BBCALL app_DDWasLost()
 {
 return (_b3d_pddsPrim && (DD_OK != _b3d_pddsPrim->IsLost()));
 }


// Usage ====================================================================
// On Start Up --------------------------------------------------------------
Graphics3D ...
SetBuffer BackBuffer()
If Not app_DDHook( SystemProperty( "DirectDraw7" ) ) Then /* Error */

// On Shut Down -------------------------------------------------------------
app_DDUnHook()
EndGraphics

// During Main Loop ---------------------------------------------------------
If app_DDWasLost() Then /* reset display, reload graphics */
UpdateWorld: RenderWorld: Flip 

I see that in my first post above, I stated that on losing the surfaces, I do a restoreAllSurfaces. Actually, I just do something like
app_DDUnHook()
EndGraphics
Graphics3D ...
SetBuffer BackBuffer()
app_DDHook( SystemProperty( "DirectDraw7" )
; Reload all graphics

It's a brute force way but I feel more at ease just tearing everything down, and building it all back up.

HTH,
David


Kev(Posted 2007) [#6]
nice fix you have there DGuy, this would be great for winblitz3d.

kev


Mikele(Posted 2007) [#7]
Could you post compiled version?


Kev(Posted 2007) [#8]
Mikele beta v1.1 of winblitz3d now contains the above fix, this can be found here.

http://www.winblitz3d.co.uk/forum/viewforum.php?f=12

however should you just like the fix in .dll i would be happy to create a .dll if DGuy does not want to or have time to.

anyways a big thanks to DGuy, and all credit due.

kev


Mikele(Posted 2007) [#9]
Thanks Kev and DGuy! :)


DGuy(Posted 2007) [#10]
Just to be complete ...

Under WinXP, another action which can cause a MAV, which was touched upon in this thread http://www.blitzbasic.com/Community/posts.php?topic=67841 , is the pressing of WinKey+L (Log-Off). Pressing this key combination causes a MAV within RenderWorld when the application regains focus.

Interestingly, this is not caught by a check for lost DirectDraw surfaces. A complete dump of all surface information just before the call to RenderWorld shows no lost surfaces. It seems the log-off is causing some other part of B3D to generate a MAV.

The work around I came up with was to detect when WinKey+L had been pressed and reset B3D (just like when a lost directdraw surface is detected). The problem was detecting when WinKey+L had been pressed, as there is no specific windows message generated and it appears to the application that it is simply losing focus.

What I noticed after viewing the messages received (Winspector is great!), was if just WinKey was pressed (which brings up the Start Menu) a WM_KEYDOWN/WM_KEYUP pair for WinKey was being generated before the app received WM_ACTIVEATEAPP indicating focus had been lost and the lParam != 0x0 (lParam indicates the handle of the window receiving focus). But, if WinKey+L was pressed, the app received ONLY a WM_KEYDOWN message for WinKey before it received the WM_ACTIVATEAPP message: No WM_KEYUP message for WinKey was being generated, and, in addition lParam == 0x0.

So, I simply check for WinKey WM_KEYDOWN/KEYUP messages an set/clear a flag, then whenever my app is about to lose focus, the flag is checked. If the flag is set, it is very likely the user is logging out in which case another flag is set indicating a possible log-out. Then just before calls to RenderWorld, the possible-log-out-flag is checked and B3D reset if needed.

Below is the relevant code (it can be added to the DirectDraw surface check code above):

; Blitz3D =======================================================
app_init%(hwnd%):"_app_init@4"
app_uninit():"_app_uninit@0"
app_possibleLogOut%():"_app_possibleLogOut@0"
app_clearPossibleLogOut():"_app_clearPossibleLogOut@0"


// C++ =======================================================
//------------------------------------------------------------
static BOOL _winKeyIsDown;
static BOOL _possibleLogOut;


//------------------------------------------------------------
// Intercepts & examines window messages recevied by Blitz3D
LRESULT CALLBACK _AppBase_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 {
 switch( uMsg )
  {
  case WM_KEYDOWN: _winKeyIsDown = ((wParam == VK_LWIN) || (wParam == VK_RWIN)); break;
  case WM_KEYUP  : _winKeyIsDown = !((wParam == VK_LWIN) || (wParam == VK_RWIN)); break;
  case WM_ACTIVATEAPP:
   {
   if( (wParam == FALSE) && (lParam == 0x0) ) _possibleLogOut = _winKeyIsDown;
   _winKeyIsDown = FALSE;
   }
  break;
  }
 return CallWindowProc( _b3d_windowProc, hwnd, uMsg, wParam, lParam ); 
 }


//------------------------------------------------------------
// Should be called as soon as possible within B3D app.
// Usage: if app_init( SystemProperty( "AppHWND" ) ) then ...
BBDECL BOOL BBCALL app_init( HWND hwnd )
 {
 _b3d_hwnd = hwnd;
 _b3d_windowProc = (WNDPROC)SetWindowLong( _b3d_hwnd, GWL_WNDPROC, (LONG)_AppBase_WindowProc );
 return TRUE;
 }


//------------------------------------------------------------ 
// Should be called just before B3D app ends.
// Usage: app_uninit()
BBDECL void BBCALL app_uninit()
 {
 SetWindowLong( _b3d_hwnd, GWL_WNDPROC, (LONG)_b3d_windowProc );
 _b3d_hwnd = 0;
 }


//-----------------------------------------------------------
// Should be called just before calls to RenderWorld().
// Usage:
//  if app_possibleLogOut() then
//    app_clearPossibleLogOut()
//    /* reset B3D */
//  else
//    RenderWorld: Flip
//  EndIf
BBDECL BOOL BBCALL app_possibleLogOut() { return _possibleLogOut; }


//-----------------------------------------------------------
// Should be called after app_possibleLogOut() has returned TRUE
// Usage: see above
BBDECL void BBCALL app_clearPossibleLogOut() { _possibleLogOut = FALSE; }

The above code dropped MAVs on log-out from 100% to almost 0%: Yes, there is still the *VERY* rare MAV on log-out. I'm thinking it's due to the log-out occuring after the log-out check but before RenderWorld has completed.

NOTE: Under Vista, the WinKey+L combination is caught by the check for lost DirectDraw surfaces.

HTH,
David


popcade(Posted 2007) [#11]
Hi, DGuy, is there're a bare-bone DLL for this sole purpose?
This will help a lot of users indeed.


DGuy(Posted 2007) [#12]
Yoko,
I could put together a simplfied version of my DLL w/ source code but I have no place on the web to upload it so others can download it ... :(

Any (free, Blitz friendly) suggestions ?

Kev, would you be willing to make it available via your site ?

David


Kev(Posted 2007) [#13]
DGuy, yes build the .dll and email it to me. ive the room to host it.

kev


@rtur(Posted 2007) [#14]
I can put it on my hosting server.
My email: arthur@...


popcade(Posted 2007) [#15]
Send to

rpgchina@...

I can help put files on my personal space.


DGuy(Posted 2007) [#16]
Kev, @rtur, Yoko ... an email with the compiled DLL + source code has been sent to each of you.

The subject is:

"B3D_AppBase.DLL - To help prevent MAVs under Blitz"

Let me know, if you received everything ok.

I've also started a new topic here:

http://www.blitzbasic.com/Community/posts.php?topic=69372

When/if download URLs become available, post them there.

Thanks,
David


popcade(Posted 2007) [#17]
Hi, I'm working in the office, would you mind send a copy to my at-work mail? It's yoxola@... and I can post it right away, thanks.


Kev(Posted 2007) [#18]
the compiled .dll is available direct from the clicky below, for more info see DGuy's post above.

http://www.winblitz3d.co.uk/B3D_AppBase.zip

kev


popcade(Posted 2007) [#19]
Thanks Kev, mirrored this in

http://icworx.org/_ext/B3D_AppBase.zip


@rtur(Posted 2007) [#20]
Thanks David, here is my mirror:

http://www.master-of-defense.com/upload/B3D_AppBase.zip