/* *@@sourcefile except.h: * header file for except.c. See remarks there. * * Note: Version numbering in this file relates to XWorkplace version * numbering. * *@@include #define INCL_DOSEXCEPTIONS *@@include #define INCL_DOSPROCESS *@@include #include *@@include #include *@@include #include *@@include #include "helpers\except.h" */ /* * Copyright (C) 1999-2000 Ulrich M”ller. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, in version 2 as it comes in the COPYING * file of the XFolder main distribution. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #if __cplusplus extern "C" { #endif #ifndef EXCEPT_HEADER_INCLUDED #define EXCEPT_HEADER_INCLUDED #if defined __IBMCPP__ || defined __IBMC__ #ifndef INCL_DOSEXCEPTIONS #error except.h requires INCL_DOSEXCEPTIONS to be defined. #endif #ifndef INCL_DOSPROCESS #error except.h requires INCL_DOSPROCESS to be defined. #endif #ifndef __stdio_h #error except.h requires stdio.h to be included. #endif #ifndef __setjmp_h #error except.h requires setjmp.h to be included. #endif #endif /******************************************************************** * * Declarations * ********************************************************************/ // forward declaration typedef struct _EXCEPTIONREGISTRATIONRECORD2 *PEXCEPTIONREGISTRATIONRECORD2; // "OnKill" function prototype for EXCEPTIONREGISTRATIONRECORD2 // added V0.9.0 (99-10-22) [umoeller] // removed V0.9.7 (2000-12-08) [umoeller] // typedef VOID APIENTRY FNEXCONKILL(PEXCEPTIONREGISTRATIONRECORD2); // typedef FNEXCONKILL *PFNEXCONKILL; /* *@@ EXCEPTIONREGISTRATIONRECORD2: * replacement EXCEPTIONREGISTRATIONRECORD * struct for thread exception handling. * * Note: code within a TRY{}CATCH block can change * pszFmt and ulArgX whenever needed to help identify * the cause of an exception */ typedef struct _EXCEPTIONREGISTRATIONRECORD2 { PVOID pNext; // as in EXCEPTIONREGISTRATIONRECORD PFN pfnHandler; // as in EXCEPTIONREGISTRATIONRECORD jmp_buf jmpThread; // additional buffer for setjmp EXCEPTIONREPORTRECORD err; // exception handlers copy the report rec here PVOID pvUser; // user ptr - set to &pszSetBy by TRY_V2 PSZ pszSetBy; // the file & function that set the handler PSZ pszFmt; // format string for fprintf() - can be null ULONG ulArg1; // arg1 for pszFmt ULONG ulArg2; // arg2 for pszFmt ULONG ulArg3; // arg3 for pszFmt ULONG ulArg4; // arg4 for pszFmt } EXCEPTIONREGISTRATIONRECORD2; /* *@@ EXCEPTSTRUCT: * structure used with TRY_xxx macros. */ typedef struct _EXCEPTSTRUCT { EXCEPTIONREGISTRATIONRECORD2 RegRec2; ULONG ulExcpt; // != NULL if exception caught APIRET arc; // rc of DosSetExceptionHandler } EXCEPTSTRUCT, *PEXCEPTSTRUCT; // function prototypes for exception hooks (V0.9.0) // "open traplog file" hook typedef FILE* APIENTRY FNEXCOPENFILE(VOID); typedef FNEXCOPENFILE *PFNEXCOPENFILE; // "exception" hook typedef VOID APIENTRY FNEXCHOOK(FILE*, PTIB, ULONG); // V0.9.16 (2001-12-02) [pr] typedef FNEXCHOOK *PFNEXCHOOK; // "error" hook typedef VOID APIENTRY FNEXCHOOKERROR(const char *pcszFile, ULONG ulLine, const char *pcszFunction, APIRET arc); typedef FNEXCHOOKERROR *PFNEXCHOOKERROR; /******************************************************************** * * Prototypes * ********************************************************************/ VOID _Optlink excExplainException(FILE *file, PSZ pszHandlerName, PEXCEPTIONREPORTRECORD pReportRec, PCONTEXTRECORD pContextRec); VOID _Optlink excExplainException2(FILE *file, PSZ pszHandlerName, PEXCEPTIONREPORTRECORD pReportRec, PCONTEXTRECORD pContextRec, PEXCEPTIONREGISTRATIONRECORD2 pRegRec2); VOID excRegisterHooks(PFNEXCOPENFILE pfnExcOpenFileNew, PFNEXCHOOK pfnExcHookNew, PFNEXCHOOKERROR pfnExcHookError, BOOL fBeepOnExceptionNew); ULONG _System excHandlerLoud(PEXCEPTIONREPORTRECORD pReportRec, PEXCEPTIONREGISTRATIONRECORD2 pRegRec2, PCONTEXTRECORD pContextRec, PVOID pv); ULONG _System excHandlerQuiet(PEXCEPTIONREPORTRECORD pReportRec, PEXCEPTIONREGISTRATIONRECORD2 pRegRec2, PCONTEXTRECORD pContextRec, PVOID pv); extern PFNEXCHOOKERROR G_pfnExcHookError; extern ULONG G_ulExplainExceptionRunning; /******************************************************************** * * Macros * ********************************************************************/ /* See except.c for explanations how to use these. */ #ifdef __NO_EXCEPTION_HANDLERS__ // exception handlers can completely be disabled #define TRY_LOUD6(excptstruct, fmt, arg1, arg2, arg3, arg4) #define TRY_LOUD(excptstruct) #define FMT_WNDPROC #else // avoid problems if header and source are different versions #define TRY_V2 1 #ifdef __NO_LOUD_EXCEPTION_HANDLERS__ #define TRY_LOUD6 TRY_QUIET6 #else // __NO_LOUD_EXCEPTION_HANDLERS__ #define TRY_LOUD6(excptstruct, fmt, arg1, arg2, arg3, arg4) \ { \ EXCEPTSTRUCT excptstruct = {0}; \ excptstruct.RegRec2.pfnHandler = (PFN)excHandlerLoud; \ excptstruct.RegRec2.pvUser = &excptstruct.RegRec2.pszSetBy; \ excptstruct.RegRec2.pszSetBy = __FILE__##"::"##__FUNCTION__##"()"; \ excptstruct.RegRec2.pszFmt = fmt; \ excptstruct.RegRec2.ulArg1 = (ULONG)arg1; \ excptstruct.RegRec2.ulArg2 = (ULONG)arg2; \ excptstruct.RegRec2.ulArg3 = (ULONG)arg3; \ excptstruct.RegRec2.ulArg4 = (ULONG)arg4; \ excptstruct.arc = DosSetExceptionHandler( \ (PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); \ if (excptstruct.arc) \ if (G_pfnExcHookError) \ G_pfnExcHookError(__FILE__, __LINE__, __FUNCTION__, excptstruct.arc); \ else \ DosBeep(1000, 1000); \ excptstruct.ulExcpt = setjmp(excptstruct.RegRec2.jmpThread); \ if (excptstruct.ulExcpt == 0) \ { #endif // __NO_LOUD_EXCEPTION_HANDLERS__ #define TRY_LOUD(excptstruct) \ TRY_LOUD6(excptstruct, 0, 0, 0, 0, 0) #define TRY_LOUD2(excptstruct, fmt) \ TRY_LOUD6(excptstruct, fmt, 0, 0, 0, 0) #define TRY_LOUD3(excptstruct, fmt, arg1) \ TRY_LOUD6(excptstruct, fmt, arg1, 0, 0, 0) #define TRY_LOUD4(excptstruct, fmt, arg1, arg2) \ TRY_LOUD6(excptstruct, fmt, arg1, arg2, 0, 0) #define TRY_LOUD5(excptstruct, fmt, arg1, arg2, arg3) \ TRY_LOUD6(excptstruct, fmt, arg1, arg2, arg3, 0) #define TRY_WNDPROC_FMT "hwnd= %08x msg= %04x mp1= %08x mp2= %08x\n" #define TRY_WNDPROC(excptstruct, hwd) \ TRY_LOUD6(excptstruct, TRY_WNDPROC_FMT, hwd, msg, mp1, mp2) #endif #ifdef __NO_EXCEPTION_HANDLERS__ // exception handlers can completely be disabled #define TRY_QUIET6(excptstruct, fmt, arg1, arg2, arg3, arg4) #define TRY_QUIET(excptstruct) #else #define TRY_QUIET6(excptstruct, fmt, arg1, arg2, arg3, arg4) \ { \ EXCEPTSTRUCT excptstruct = {0}; \ excptstruct.RegRec2.pfnHandler = (PFN)excHandlerQuiet; \ excptstruct.RegRec2.pvUser = &excptstruct.RegRec2.pszSetBy; \ excptstruct.RegRec2.pszSetBy = __FILE__##"::"##__FUNCTION__##"()"; \ excptstruct.RegRec2.pszFmt = fmt; \ excptstruct.RegRec2.ulArg1 = arg1; \ excptstruct.RegRec2.ulArg2 = arg2; \ excptstruct.RegRec2.ulArg3 = arg3; \ excptstruct.RegRec2.ulArg4 = arg4; \ excptstruct.arc = DosSetExceptionHandler( \ (PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); \ if (excptstruct.arc) \ if (G_pfnExcHookError) \ G_pfnExcHookError(__FILE__, __LINE__, __FUNCTION__, excptstruct.arc); \ else \ DosBeep(1000, 1000); \ excptstruct.ulExcpt = setjmp(excptstruct.RegRec2.jmpThread); \ if (excptstruct.ulExcpt == 0) \ { #define TRY_QUIET(excptstruct) \ TRY_QUIET6(excptstruct, 0, 0, 0, 0, 0) #endif #ifdef __NO_EXCEPTION_HANDLERS__ // exception handlers can completely be disabled #define CATCH(excptstruct) if (FALSE) { #else #define CATCH(excptstruct) \ DosUnsetExceptionHandler( \ (PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); \ } /* end of TRY block */ \ else \ { /* exception occurred: */ \ DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&(excptstruct.RegRec2)); #endif #ifdef __NO_EXCEPTION_HANDLERS__ // exception handlers can completely be disabled #define END_CATCH() } #else #define END_CATCH() \ } /* end of exception-occurred block */ \ } #endif /* * CRASH: * this macro is helpful for testing * the exception handlers. * This is not for general use. ;-) */ #define CRASH {PSZ p = NULL; *p = 'a'; } #endif // EXCEPT_HEADER_INCLUDED #if __cplusplus } #endif