mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-10 06:31:48 +00:00
added exception/signal/exit handlers to properly restore modified system settings like gamma ramps
This commit is contained in:
parent
d8bf2665f5
commit
39ee0db5b7
11 changed files with 280 additions and 81 deletions
|
@ -698,8 +698,6 @@ static void CL_FirstSnapshot()
|
|||
Cbuf_AddText( cl_activeAction->string );
|
||||
Cvar_Set( "activeAction", "" );
|
||||
}
|
||||
|
||||
Sys_BeginProfiling();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1892,6 +1892,9 @@ int Com_Milliseconds()
|
|||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
|
||||
// throw a fatal error to test error shutdown procedures
|
||||
|
||||
static void Com_Error_f( void )
|
||||
|
@ -1921,6 +1924,12 @@ static void Com_Freeze_f( void )
|
|||
}
|
||||
|
||||
|
||||
static void Com_Exit_f( void )
|
||||
{
|
||||
exit( 666 );
|
||||
}
|
||||
|
||||
|
||||
// force a bus error for development reasons
|
||||
|
||||
static void Com_Crash_f( void )
|
||||
|
@ -1929,6 +1938,9 @@ static void Com_Crash_f( void )
|
|||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// TTimo: centralizing the cl_cdkey stuff after I discovered a buffer overflow problem with the dedicated server version
|
||||
// not sure it's necessary to have different defaults for regular and dedicated, but I don't want to risk it
|
||||
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=470
|
||||
|
@ -2211,12 +2223,12 @@ void Com_Init( char *commandLine )
|
|||
}
|
||||
}
|
||||
|
||||
if ( com_developer && com_developer->integer ) {
|
||||
Cmd_AddCommand( "error", Com_Error_f );
|
||||
Cmd_AddCommand( "crash", Com_Crash_f );
|
||||
Cmd_AddCommand( "freeze", Com_Freeze_f );
|
||||
//Cmd_AddCommand( "changeVectors", MSG_ReportChangeVectors_f );
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
Cmd_AddCommand( "error", Com_Error_f );
|
||||
Cmd_AddCommand( "crash", Com_Crash_f );
|
||||
Cmd_AddCommand( "freeze", Com_Freeze_f );
|
||||
Cmd_AddCommand( "exit", Com_Exit_f );
|
||||
#endif
|
||||
|
||||
Cmd_AddCommand( "quit", Com_Quit_f );
|
||||
Cmd_AddCommand( "writeconfig", Com_WriteConfig_f );
|
||||
|
|
|
@ -976,9 +976,6 @@ const char* Sys_DefaultHomePath();
|
|||
char** Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, qbool wantsubs );
|
||||
void Sys_FreeFileList( char **list );
|
||||
|
||||
void Sys_BeginProfiling( void );
|
||||
void Sys_EndProfiling( void );
|
||||
|
||||
qbool Sys_LowPhysicalMemory( void );
|
||||
|
||||
|
||||
|
|
|
@ -867,6 +867,7 @@ static int vidmode_MajorVersion = 0, vidmode_MinorVersion = 0; // major and mino
|
|||
|
||||
// gamma value of the X display before we start playing with it
|
||||
static XF86VidModeGamma vidmode_InitialGamma = { -1,-1,-1 }; // drakkar - initialized to nonvalid values
|
||||
static qbool vidmode_GammaSet = qfalse;
|
||||
#endif /* HAVE_XF86DGA */
|
||||
|
||||
#ifdef HAVE_XF86DGA
|
||||
|
@ -900,10 +901,26 @@ void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned
|
|||
gamma.red = g;
|
||||
gamma.green = g;
|
||||
gamma.blue = g;
|
||||
XF86VidModeSetGamma(dpy, scrnum, &gamma);
|
||||
if (XF86VidModeSetGamma(dpy, scrnum, &gamma))
|
||||
{
|
||||
vidmode_GammaSet = qtrue;
|
||||
}
|
||||
#endif /* HAVE_XF86DGA */
|
||||
}
|
||||
|
||||
void LIN_RestoreGamma( void )
|
||||
{
|
||||
#ifdef HAVE_XF86DGA
|
||||
if (dpy && glConfig.deviceSupportsGamma && vidmode_GammaSet)
|
||||
{
|
||||
if (XF86VidModeSetGamma(dpy, scrnum, &vidmode_InitialGamma) == True)
|
||||
{
|
||||
vidmode_GammaSet = qfalse;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** GLimp_Shutdown
|
||||
**
|
||||
|
@ -933,10 +950,7 @@ void GLimp_Shutdown( void )
|
|||
#ifdef HAVE_XF86DGA
|
||||
if (vidmode_active)
|
||||
XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
|
||||
if (glConfig.deviceSupportsGamma)
|
||||
{
|
||||
XF86VidModeSetGamma(dpy, scrnum, &vidmode_InitialGamma);
|
||||
}
|
||||
LIN_RestoreGamma();
|
||||
#endif /* HAVE_XF86DGA */
|
||||
|
||||
// NOTE TTimo opening/closing the display should be necessary only once per run
|
||||
|
@ -1401,8 +1415,6 @@ void GLimp_Init( void )
|
|||
}
|
||||
#endif
|
||||
|
||||
InitSig();
|
||||
|
||||
// set up our custom error handler for X failures
|
||||
XSetErrorHandler(&qXErrorHandler);
|
||||
|
||||
|
@ -1429,8 +1441,6 @@ void GLimp_Init( void )
|
|||
QGL_InitARB(); // compiles the shaders etc
|
||||
QGL_SwapInterval( dpy, win, r_swapInterval->integer );
|
||||
|
||||
InitSig(); // not clear why this is at begin & end of function
|
||||
|
||||
IN_Init();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr );
|
||||
void Sys_SendKeyEvents (void);
|
||||
void Sys_Exit(int);
|
||||
|
||||
// Input subsystem
|
||||
void IN_Init (void);
|
||||
|
@ -37,4 +38,7 @@ void QGL_EnableLogging( qboolean enable );
|
|||
void QGL_Shutdown( void );
|
||||
|
||||
// signals.c
|
||||
void InitSig(void);
|
||||
void SIG_Init(void);
|
||||
|
||||
// hardware gamma ramp
|
||||
void LIN_RestoreGamma(void);
|
||||
|
|
|
@ -26,39 +26,133 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#ifndef DEDICATED
|
||||
#include "../renderer/tr_local.h"
|
||||
#endif
|
||||
#include "linux_local.h"
|
||||
|
||||
static qboolean signalcaught = qfalse;;
|
||||
|
||||
void Sys_Exit(int); // bk010104 - abstraction
|
||||
// columns: Symbol, IsCrash, Desc
|
||||
#define SIGNAL_LIST(X) \
|
||||
X(SIGHUP, qfalse, "hangup detected on controlling terminal or death of controlling process") \
|
||||
X(SIGQUIT, qfalse, "quit from keyboard") \
|
||||
X(SIGILL, qtrue, "illegal instruction") \
|
||||
X(SIGTRAP, qfalse, "trace/breakpoint trap") \
|
||||
X(SIGIOT, qtrue, "IOT trap (a synonym for SIGABRT)") \
|
||||
X(SIGBUS, qtrue, "bus error (bad memory access)") \
|
||||
X(SIGFPE, qtrue, "fatal arithmetic error") \
|
||||
X(SIGSEGV, qtrue, "invalid memory reference") \
|
||||
X(SIGTERM, qfalse, "termination signal") \
|
||||
X(SIGINT, qfalse, "interrupt")
|
||||
|
||||
static void signal_handler(int sig) // bk010104 - replace this... (NOTE TTimo huh?)
|
||||
|
||||
static qboolean Sig_IsCrashSignal(int sig)
|
||||
{
|
||||
if (signalcaught)
|
||||
{
|
||||
printf("DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", sig);
|
||||
Sys_Exit(1); // bk010104 - abstraction
|
||||
}
|
||||
#define SIGNAL_ITEM(Symbol, IsCrash, Desc) case Symbol: return IsCrash;
|
||||
switch (sig) {
|
||||
SIGNAL_LIST(SIGNAL_ITEM)
|
||||
default: return qfalse;
|
||||
}
|
||||
#undef SIGNAL_ITEM
|
||||
}
|
||||
|
||||
signalcaught = qtrue;
|
||||
printf("Received signal %d, exiting...\n", sig);
|
||||
|
||||
static const char* Sig_GetDescription(int sig)
|
||||
{
|
||||
#define SIGNAL_ITEM(Symbol, IsCrash, Desc) case Symbol: return Desc;
|
||||
switch (sig) {
|
||||
SIGNAL_LIST(SIGNAL_ITEM)
|
||||
default: return "unhandled signal";
|
||||
}
|
||||
#undef SIGNAL_ITEM
|
||||
}
|
||||
|
||||
|
||||
static const char* Sig_GetName(int sig)
|
||||
{
|
||||
#define SIGNAL_ITEM(Symbol, IsCrash, Desc) case Symbol: return #Symbol;
|
||||
switch (sig) {
|
||||
SIGNAL_LIST(SIGNAL_ITEM)
|
||||
default: return "unhandled signal";
|
||||
}
|
||||
#undef SIGNAL_ITEM
|
||||
}
|
||||
|
||||
|
||||
// Every call in there needs to be safe when called more than once.
|
||||
static void SIG_HandleCrash()
|
||||
{
|
||||
// We crashed and only care about restoring system settings
|
||||
// that the process clean-up won't handle for us.
|
||||
#ifndef DEDICATED
|
||||
//GLimp_Shutdown(); // bk010104 - shouldn't this be CL_Shutdown
|
||||
// rcg08312005 Agreed: changed to CL_Shutdown... --ryan.
|
||||
CL_Shutdown();
|
||||
LIN_RestoreGamma();
|
||||
#endif
|
||||
SV_Shutdown("Signal caught");
|
||||
Sys_Exit(0); // bk010104 - abstraction NOTE TTimo send a 0 to avoid DOUBLE SIGNAL FAULT
|
||||
}
|
||||
|
||||
void InitSig(void)
|
||||
|
||||
static void Sig_HandleSignal(int sig)
|
||||
{
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGQUIT, signal_handler);
|
||||
signal(SIGILL, signal_handler);
|
||||
signal(SIGTRAP, signal_handler);
|
||||
signal(SIGIOT, signal_handler);
|
||||
signal(SIGBUS, signal_handler);
|
||||
signal(SIGFPE, signal_handler);
|
||||
signal(SIGSEGV, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
static int faultCounter = 0;
|
||||
static qbool crashHandled = qfalse;
|
||||
|
||||
faultCounter++;
|
||||
|
||||
if (faultCounter >= 3)
|
||||
{
|
||||
// We're here because the double fault handler failed.
|
||||
// We take no chances this time and exit right away to avoid
|
||||
// calling this function many more times.
|
||||
exit(3);
|
||||
}
|
||||
|
||||
const qbool crashed = Sig_IsCrashSignal(sig);
|
||||
if (faultCounter == 2)
|
||||
{
|
||||
// The termination handler failed which means that if we exit right now,
|
||||
// some system settings might still be in a bad state.
|
||||
printf("DOUBLE SIGNAL FAULT: Received signal %d (%s), exiting...\n", sig, Sig_GetName(sig));
|
||||
if (crashed && !crashHandled)
|
||||
{
|
||||
SIG_HandleCrash();
|
||||
}
|
||||
exit(2);
|
||||
}
|
||||
|
||||
fprintf(crashed ? stderr : stdout, "Received %s signal %d: %s (%s), exiting...\n",
|
||||
crashed ? "crash" : "termination", sig, Sig_GetName(sig), Sig_GetDescription(sig));
|
||||
|
||||
if (crashed)
|
||||
{
|
||||
SIG_HandleCrash();
|
||||
crashHandled = qtrue;
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// attempt a proper shutdown sequence
|
||||
#ifndef DEDICATED
|
||||
CL_Shutdown();
|
||||
#endif
|
||||
SV_Shutdown("Signal caught");
|
||||
Sys_Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SIG_Init(void)
|
||||
{
|
||||
// This is unfortunately needed because some code might
|
||||
// call exit and bypass all the clean-up work without
|
||||
// there ever being a real crash.
|
||||
// This happens for instance with the "fatal IO error"
|
||||
// of the X server.
|
||||
atexit(SIG_HandleCrash);
|
||||
|
||||
signal(SIGILL, Sig_HandleSignal);
|
||||
signal(SIGIOT, Sig_HandleSignal);
|
||||
signal(SIGBUS, Sig_HandleSignal);
|
||||
signal(SIGFPE, Sig_HandleSignal);
|
||||
signal(SIGSEGV, Sig_HandleSignal);
|
||||
signal(SIGHUP, Sig_HandleSignal);
|
||||
signal(SIGQUIT, Sig_HandleSignal);
|
||||
signal(SIGTRAP, Sig_HandleSignal);
|
||||
signal(SIGTERM, Sig_HandleSignal);
|
||||
signal(SIGINT, Sig_HandleSignal);
|
||||
}
|
||||
|
|
|
@ -436,24 +436,11 @@ qboolean Sys_LowPhysicalMemory()
|
|||
}
|
||||
|
||||
|
||||
void Sys_BeginProfiling( void ) {
|
||||
}
|
||||
|
||||
|
||||
// single exit point (regular exit or in case of signal fault)
|
||||
void Sys_Exit( int ex )
|
||||
{
|
||||
Sys_ConsoleInputShutdown();
|
||||
|
||||
#ifdef NDEBUG // regular behavior
|
||||
// We can't do this as long as GL DLL's keep installing with atexit...
|
||||
//exit(ex);
|
||||
_exit(ex);
|
||||
#else
|
||||
// Give me a backtrace on error exits.
|
||||
assert( ex == 0 );
|
||||
exit(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -823,6 +810,8 @@ void Sys_Init()
|
|||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
SIG_Init();
|
||||
|
||||
// merge the command line: we need it in a single chunk
|
||||
int len = 1, i;
|
||||
for (i = 1; i < argc; ++i)
|
||||
|
@ -844,11 +833,6 @@ int main( int argc, char* argv[] )
|
|||
|
||||
fcntl( 0, F_SETFL, fcntl(0, F_GETFL, 0) | FNDELAY );
|
||||
|
||||
#ifdef DEDICATED
|
||||
// init here for dedicated, as we don't have GLimp_Init
|
||||
InitSig();
|
||||
#endif
|
||||
|
||||
while (qtrue) {
|
||||
// if running as a client but not focused, sleep a bit
|
||||
// (servers have their own sleep path)
|
||||
|
|
|
@ -41,6 +41,8 @@ typedef struct
|
|||
qbool cdsFullscreen;
|
||||
qbool pixelFormatSet;
|
||||
int nPendingPF;
|
||||
|
||||
qbool gammaRampSet; // qtrue if our custom ramp is active
|
||||
} glwstate_t;
|
||||
|
||||
extern glwstate_t glw_state;
|
||||
|
|
|
@ -842,13 +842,14 @@ static void GLW_CheckHardwareGamma()
|
|||
}
|
||||
|
||||
|
||||
static void GLW_RestoreGamma()
|
||||
void GLW_RestoreGamma()
|
||||
{
|
||||
if (!glConfig.deviceSupportsGamma)
|
||||
if (!glConfig.deviceSupportsGamma || !glw_state.gammaRampSet)
|
||||
return;
|
||||
|
||||
HDC hDC = GetDC( GetDesktopWindow() );
|
||||
SetDeviceGammaRamp( hDC, s_oldHardwareGamma );
|
||||
if ( SetDeviceGammaRamp( hDC, s_oldHardwareGamma ) )
|
||||
glw_state.gammaRampSet = qfalse;
|
||||
ReleaseDC( GetDesktopWindow(), hDC );
|
||||
}
|
||||
|
||||
|
@ -878,7 +879,9 @@ void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned
|
|||
}
|
||||
}
|
||||
|
||||
if ( !SetDeviceGammaRamp( glw_state.hDC, table ) ) {
|
||||
if ( SetDeviceGammaRamp( glw_state.hDC, table ) ) {
|
||||
glw_state.gammaRampSet = qtrue;
|
||||
} else {
|
||||
Com_Printf( "SetDeviceGammaRamp failed.\n" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,13 +43,14 @@ void SNDDMA_Activate();
|
|||
|
||||
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
||||
|
||||
void GLW_RestoreGamma();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HWND hWnd;
|
||||
HINSTANCE hInstance;
|
||||
qbool activeApp;
|
||||
qbool isMinimized;
|
||||
OSVERSIONINFO osversion;
|
||||
|
||||
// when we get a windows message, we store the time off
|
||||
// so keyboard processing can know the exact time of an event
|
||||
|
|
|
@ -36,6 +36,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
|
||||
WinVars_t g_wv;
|
||||
|
||||
|
||||
static qbool win_timePeriodActive = qfalse;
|
||||
|
||||
|
||||
static void Win_BeginTimePeriod()
|
||||
{
|
||||
if ( win_timePeriodActive )
|
||||
return;
|
||||
|
||||
timeBeginPeriod( 1 );
|
||||
win_timePeriodActive = qtrue;
|
||||
}
|
||||
|
||||
|
||||
static void Win_EndTimePeriod()
|
||||
{
|
||||
if ( !win_timePeriodActive )
|
||||
return;
|
||||
|
||||
timeEndPeriod( 1 );
|
||||
win_timePeriodActive = qfalse;
|
||||
}
|
||||
|
||||
|
||||
#define MEM_THRESHOLD 96*1024*1024
|
||||
|
@ -48,11 +71,6 @@ qbool Sys_LowPhysicalMemory()
|
|||
}
|
||||
|
||||
|
||||
void Sys_BeginProfiling( void ) {
|
||||
// this is just used on the mac build
|
||||
}
|
||||
|
||||
|
||||
// show the early console as an error dialog
|
||||
|
||||
void QDECL Sys_Error( const char *error, ... )
|
||||
|
@ -70,7 +88,7 @@ void QDECL Sys_Error( const char *error, ... )
|
|||
Sys_SetErrorText( text );
|
||||
Sys_ShowConsole( 1, qtrue );
|
||||
|
||||
timeEndPeriod( 1 );
|
||||
Win_EndTimePeriod();
|
||||
|
||||
#ifndef DEDICATED
|
||||
IN_Shutdown();
|
||||
|
@ -93,7 +111,7 @@ void QDECL Sys_Error( const char *error, ... )
|
|||
|
||||
void Sys_Quit()
|
||||
{
|
||||
timeEndPeriod( 1 );
|
||||
Win_EndTimePeriod();
|
||||
#ifndef DEDICATED
|
||||
IN_Shutdown();
|
||||
#endif
|
||||
|
@ -520,7 +538,7 @@ static void Sys_Net_Restart_f( void )
|
|||
void Sys_Init()
|
||||
{
|
||||
// make sure the timer is high precision, otherwise NT gets 18ms resolution
|
||||
timeBeginPeriod( 1 );
|
||||
Win_BeginTimePeriod();
|
||||
|
||||
#ifndef DEDICATED
|
||||
Cmd_AddCommand( "in_restart", Sys_In_Restart_f );
|
||||
|
@ -542,7 +560,7 @@ void Sys_Init()
|
|||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
|
||||
static int WinMainImpl( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
|
||||
{
|
||||
// should never get a previous instance in Win32
|
||||
if ( hPrevInstance )
|
||||
|
@ -553,9 +571,6 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
|
|||
// done before Com/Sys_Init since we need this for error output
|
||||
Sys_CreateConsole();
|
||||
|
||||
// no abort/retry/fail errors
|
||||
SetErrorMode( SEM_FAILCRITICALERRORS );
|
||||
|
||||
// get the initial time base
|
||||
Sys_Milliseconds();
|
||||
|
||||
|
@ -605,3 +620,82 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
|
|||
|
||||
// never gets here
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The exception handler's job is to reset system settings that won't get reset
|
||||
// as part of the normal process clean-up by the OS.
|
||||
// It can't do any memory allocation or use any synchronization objects.
|
||||
// Ideally, we want it to be called before every abrupt application exit
|
||||
// and right after any legitimate crash.
|
||||
//
|
||||
// There are 2 cases where the function won't be called:
|
||||
//
|
||||
// 1. Termination through the debugger.
|
||||
// Our atexit handler never gets called.
|
||||
//
|
||||
// Work-around: Quit normally.
|
||||
//
|
||||
// 2. Breakpoints. The debugger has first-chance access and handles them.
|
||||
// Our exception handler doesn't get called.
|
||||
//
|
||||
// Work-around: None for debugging. Quit normally.
|
||||
//
|
||||
|
||||
|
||||
static qbool exitCalled = qfalse;
|
||||
|
||||
|
||||
LONG CALLBACK Win_HandleException( EXCEPTION_POINTERS* ep )
|
||||
{
|
||||
static const char* mbMsg = "CNQ3 crashed!\n\nOK to continue after attaching a debugger\nCancel to quit";
|
||||
|
||||
#if !DEDICATED
|
||||
__try {
|
||||
GLW_RestoreGamma();
|
||||
} __except( EXCEPTION_EXECUTE_HANDLER ) {}
|
||||
#endif
|
||||
|
||||
__try {
|
||||
Win_EndTimePeriod();
|
||||
} __except( EXCEPTION_EXECUTE_HANDLER ) {}
|
||||
|
||||
if ( exitCalled || IsDebuggerPresent() )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
// ask if we want to debug the app
|
||||
if ( MessageBoxA( NULL, mbMsg, "Crash", MB_OKCANCEL | MB_ICONERROR ) == IDOK &&
|
||||
IsDebuggerPresent() )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
#endif
|
||||
|
||||
ExitProcess( 666 );
|
||||
}
|
||||
|
||||
|
||||
static void Win_HandleExit( void )
|
||||
{
|
||||
exitCalled = qtrue;
|
||||
Win_HandleException( NULL );
|
||||
}
|
||||
|
||||
|
||||
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
|
||||
{
|
||||
// Register the exception handler for all threads present and future in this process.
|
||||
// 1 means we're inserting the handler at the front of the queue.
|
||||
// The debugger does still get first-chance access though.
|
||||
// The handler is always called in the context of the thread raising the exception.
|
||||
AddVectoredExceptionHandler( 1, Win_HandleException );
|
||||
|
||||
// Make sure we reset system settings even when someone calls exit.
|
||||
atexit( Win_HandleExit );
|
||||
|
||||
// SetErrorMode(0) gets the current flags
|
||||
// SEM_FAILCRITICALERRORS -> no abort/retry/fail errors
|
||||
// SEM_NOGPFAULTERRORBOX -> the Windows Error Reporting dialog will not be shown
|
||||
SetErrorMode( SetErrorMode(0) | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
|
||||
|
||||
return WinMainImpl( hInstance, hPrevInstance, lpCmdLine, nCmdShow );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue