Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

RunTime Debug and Error Handling Part III - Find that elusive bug

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin RunTime Debug and Error Handling Part III - Find that elusive bug

    My latest attempt at "Global" Error Handling

    ErrorHandler.inc
    Code:
    '*** ErrorHandling.inc
    '***      Written by: Cliff Nichols - 08-28-2008
    '***      Modified by: Cliff Nichols - 06-28-2009
    '***
    '***      Compilers Tested:   8.04/9.0/9.01
    '***      Should work on:     7/8/9
    '***
    '***      OS'es Tested:       XP-Pro SP3, Vista-Ultimate
    '***      Should work on:     95/98/ME/NT/2K/XP/Vista
    '***
    '***      Purpose - Beefed up Error Handling Routines to attempt to "Bullet-Proof" apps
    '***                Via a "GLOBAL ERROR HANDLER" (Which in theory does not exist)
    '***      Concepts:
    '***                Demonstrate PB Errors - (How each either sets or raises an error window)
    '***                Demonstrate Windows Errors - (How each either sets or raises an error window)
    '***                Demonstrate GPF "EXCEPTIONS" - (The errors you see with the cryptic
    '***                                                   "Had a problem and has to close" for an explaination
    '***                                                   , but no plain english why the error?)
    '***
    '***      Special Thnx:
    '***                Paul Dixon - Without whom, I would not have found out about EIP's and beginning to understand
    '***                               how to decipher assembly code (still learning so this INC is not complete...YET!!!! that is)
    '--------------------------------------------------------------------------------
    '*** Now for the FUN Stuff
    '***      PB has 'On Error' for handling errors on the DDT side
    '***           PB (DDT) can set an error with ERR = some number (does not raise an error, just sets the value)
    '***           PB (DDT) can raise an error just by ERROR = some number
    '***           PB (DDT) can test an error state by checking the value of ERR
    '***           PB appears to work with 'On Error' for handling errors on the SDK side for most errors
    '***      Windows uses Exceptions (But you must handle, or ignore to not generate a GPF)       '<--- This statement may not be TOTALLY correct, but still is concise
    '***           Windows (SDK) can set an error with 'SetLastError (does not raise an error, just sets the value)
    '***           Windows (SDK) can set an error with parameters using 'SetLastErrorEX (does not raise an error, just sets the value)
    '***           Windows (SDK) can raise an error with 'RaiseException' api call
    '***           Windows (SDK) can test an error state by 'GetLastError'
    '***
    '***      Windows has "Exceptions" (You've seen them...the default usually shows the typical "*.exe has encountered a problem and needs to close" message)
    '***           Windows "Exceptions" can be raised, but default handler is typically fatal, but you can override that fatality
    '***
    '***      PB narrowing down to line that caused the error
    '***           Manually inserting Line Numbers can definitely nail down an error, but either needs to be done by hand, or pre-compile to do it for you
    '*** ---> Scratch that thought, I now have figured out using a macro that I call "DebugLine" can be used on the same line as code, or a separate line
    '*** ---> to "Land-Mark" by inserting a line number in your code at compile time (Disperce anywhere you think you want a landmark to home in on an error)
    '***
    '***           PB Line numbers (if inserted) can assist in locating where an error occured (larger projects its smarter to contain line numbers to their functions)
    '***           PB FUNCNAME$ in conjunction with the line numbers can nail down what line the error occured on
    '***
    '***      Windows narrowing down to line that caused the error
    '***           Extended Instruction Pointer (EIP)      --->      to be worked on and detailed later
    '***      Conjunction, junction, whats your function??? :-)
    '***
    '*** Out of the ordinary ideas:
    '***      No Globals - Use functions to store value of "Global" and look up the value when needed        '<--- Not 100% on this yet, but no problems either
    '***      Locating lines of code - Figuring out what line of readable code I am on, from the machine code that I read
    '***                               (only beginning, so take at face value, and please correct me where I am wrong)
    '***      Macro's - Usually I have no use for them, because if I use the same code in multiple functions,
    '***                     then I just write a function to be called from each function.
    '***                     But in a case like this where variables are only valid locally,
    '***                     I can see using macros to replace my code at compile time can save a ton a space
    '***                     and be more readable in the future
    '***
    '***
    '--------------------------------------------------------------------------------
    
    '*** If not already declared in your code, then declare this INC
    #IF NOT %DEF(%ERRORHANDLING)
         %ERRORHANDLING = 1
    '*** Globals
    '***      NONE
    '*** OverRideError flag can be one of the following values:
    '***      %UNKNOWN_VALUE = Unknown until user input at run-time
    '***      %NORESUME = Do not resume
    '***      %RESUME = Resume at same line of code that caused the error.
    '***                (Error must be corrected or will result in an infinite loop)
    '***      %RESUMENEXT = Resume at line after code that caused the error.
    '***      %CRASH = Purposely allow a Crash (GPF) to happen.
    '***
         %UNKNOWN_VALUE = -1                                                                  'Unknown for when I do not know the value until runtime
    '*** <--- I chose RESUMENEXT to be 0 if for the odd chance that a flag is not set (default is 0) that I do NOT cause an infinite loop
         %RESUME = 1                                                                          'Use 1 to resume (this is so that if left out, then not stuck in an infinite loop)
         %RESUMENEXT = 0                                                                      'Use 0 for Resume Next in case flag is not set to avoid infinite loops
         %NORESUME = -1                                                                       'NoResume = UnKnown so that code decides what is best path to follow
         %CRASH = %INVALID_HANDLE_VALUE                                                       'Purposely allow crash of App
    '*** Constants not found in Win32Api.Inc (Have to be re-researched because I found %EXCEPTION_ILLEGAL_INSTRUCTION = %STATUS_ILLEGAL_INSTRUCTION
    '     %EXCEPTION_ILLEGAL_INSTRUCTION  = &HC000001D
         %EXCEPTION_ILLEGAL_INSTRUCTION = %STATUS_ILLEGAL_INSTRUCTION
         %EXCEPTION_STACK_OVERFLOW       = &HC00000FD
         %EXCEPTION_INVALID_DISPOSITION  = &HC0000026
         %EXCEPTION_NONCONTINUABLE_EXCEPTION = &HC0000025
    '*** Type to hold my settings
    TYPE ErrorCodes
         lpEP AS EXCEPTION_POINTERS PTR                                                       'Windows EXCEPTIONS (Errors)
         SafePointer AS LONG                                                                  'Pointer value to ErrHandler
         ErrorLogNumber AS LONG                                                               'Handle to log file
         LogError AS LONG                                                                     'If logging errors
         PbErrorValue AS LONG                                                                 'PB ERR
         WinErrorValue AS LONG                                                                'GetLastError
         AppErrorValue AS LONG                                                                'Error value reguardless of PB Error or Windows Error
         PbErrorDesc AS ASCIIZ * %MAX_PATH                                                    'PB Description of Error in plain english
         WinErrorDesc AS ASCIIZ * %MAX_PATH                                                   'Windows Description of Error in plain english
         AppErrorDesc AS ASCIIZ * %MAX_PATH                                                   'Application Specific Description of Error
         CodeModule AS ASCIIZ * %MAX_PATH                                                     'Function that caused the error         '<--- MOST Important thing I have always been after in larger projects)
         LineLabelNumber AS ASCIIZ * %MAX_PATH                                                'Line number (or Variable) that was last passed before the error
         OverRideError AS LONG                                                                'Variable for if to continue even if there is an error
         StringValue AS ASCIIZ * %MAX_PATH                                                    'Error value as a string
         Desc AS ASCIIZ * %MAX_PATH                                                           'Description for loggin purposes to help track down a problem
    END TYPE
    
    '*** Declare Functions
    
    '*************************************************************************************************************
    '*** Macro's - When Compiled, replace the name of the macro with all the functions and processes in the macro
    '***           As if you had done it yourself in each and every SUB/FUNCTION it was called
    '***           Do not add line numbers to Macro's unless you want to renumber functions that use the macros
    '*************************************************************************************************************
    '*** Using SetUnhandledExceptionFilter you can over-ride the default error handler for windows
    '***      SetUnhandledExceptionFilter %NULL                           = Default handling within UnhandledExceptionFilter
    '***      SetUnhandledExceptionFilter %EXCEPTION_EXECUTE_HANDLER      = Return from UnhandledExceptionFilter and execute the associated exception handler.
    '***                                                                       (Usually results in process termination.)
    '***      SetUnhandledExceptionFilter %EXCEPTION_CONTINUE_EXECUTION   = Return from UnhandledExceptionFilter and continue execution from the point of the exception.
    '***                                                                       Note that the filter function is free to modify the continuation state by modifying the exception information supplied through its LPEXCEPTION_POINTERS parameter
    '***      SetUnhandledExceptionFilter %EXCEPTION_CONTINUE_SEARCH      = Proceed with normal execution of UnhandledExceptionFilter . That means obeying the SetErrorMod flags, or invoking the Application Error pop-up message box.
    '***
    
    
    '*** OnError - Replacement for "ON ERROR"  (Place as 1st line of code in your function)
         MACRO OnError
              ON ERROR GOTO ErrHandler                                                        'PB command for On Error
              LOCAL lpEP AS EXCEPTION_POINTERS                                                'If Windows Crops up an error
              LOCAL ErrFunc AS LONG                                                           'If Error within my function
              LOCAL SoftwarePathName AS ASCIIZ * %MAX_PATH
              LOCAL ErrorLogNumber AS LONG
              LOCAL ErrorCode AS ErrorCodes
              LOCAL Continuable AS LONG
              LOCAL LinesOfCodeToSkip AS LONG
              LOCAL DebugLineNumber AS STRING
              SetGetSafeJump CODEPTR(ErrHandler), ErrorCode.SafePointer, %True                'Set flag for escaping functions that I can not find a way to continue from
    '          SetGetJumpLines 1, LinesOfCodeToSkip, %TRUE                                     'Set flag for how many lines of code to skip (default = 1 line)
              SetUnhandledExceptionFilter( CODEPTR (ExceptionHandler))                        'Over-Ride Windows default and let me decide if a FATAL error or to 'Fix-And-Continue'
              SetGetErrorCodes VARPTR(ErrorCode), %UNKNOWN_VALUE, %TRUE                       'Set a handle to ErrorCodes without using GLOBALS      '<--- Not 100% on this yet
              GetModuleFileName(GetModuleHandle(BYVAL %NULL), SoftwarePathName, %MAX_PATH)    'Get Parent PathName and Name
              SoftwarePathName = MID$(SoftwarePathName, INSTR(-1, SoftwarePathName,"\") + 1)  'Path Name
              SoftwarePathName = MID$(SoftwarePathName, 1, INSTR(SoftwarePathName,".") - 1)   'Strip the .Dll or .Exe
              SetGetLogErrors %UNKNOWN_VALUE, ErrorCode.LogError, %UNKNOWN_VALUE              'Get flag for logging errors
              SELECT CASE ErrorCode.LogError
                   CASE %FALSE
                   CASE %TRUE
                        SetGetLogFileNumber(%UNKNOWN_VALUE, ErrorCode.ErrorLogNumber, %UNKNOWN_VALUE)
                        SELECT CASE ErrorCode.ErrorLogNumber
                             CASE 0         'No file yet
                                  ErrorCode.ErrorLogNumber = FREEFILE
                                  OPEN SoftwarePathName + " Error Log.txt" FOR APPEND LOCK SHARED AS #ErrorCode.ErrorLogNumber          'Open the log file
                                  SetGetLogFileNumber(ErrorCode.ErrorLogNumber, ErrorCode.ErrorLogNumber, %TRUE)
                        END SELECT
              END SELECT
         END MACRO
    
         MACRO DebugLine
              DebugLineNumber = TRIM$(STR$(VAL(DebugLineNumber) + 1))
              ErrorCode.LineLabelNumber = DebugLineNumber
         END MACRO
    
    '*** HandleErrors - (Place as last line in your function)
         MACRO HandleErrors
              SetGetLogErrors %UNKNOWN_VALUE, ErrorCode.LogError, %UNKNOWN_VALUE         'Get flag for logging errors
              SELECT CASE ErrorCode.LogError
                   CASE %TRUE
                   CASE %FALSE
                        CLOSE ErrorCode.ErrorLogNumber                                                            'End log file
                        SetGetLogFileNumber(0, ErrorCode.ErrorLogNumber, %TRUE)
              END SELECT
              EXIT MACRO                                                                      'Exit (do not care if sub/function/method/property
         ErrHandler:                                                                          'Only gets here if an error
    '*** The following Error Information has to stay in the macro due to the error is cleared when it leaves the function that it was raised in.
              ErrorCode.PbErrorValue = ERR                                                    'Get PB Last Error
              ErrorCode.WinErrorValue = GetLastError                                          'Get API Last Error
              ExceptionInfo(ErrorCode)                                                        'Fill Information for logging
              SELECT CASE ErrorCode.OverRideError                                             'Decide how to continue
                   CASE %UNKNOWN_VALUE
                        Continuable = MSGBOX("Error: " + STR$(ErrorCode.AppErrorValue) + SPACE$(5) + "Desc: " + ErrorCode.AppErrorDesc + $CR _
                                            + " Function: " + SPACE$(5) + CALLSTK$(1) + $CR + $CR + "Ignore this error?", %MB_ICONERROR OR %MB_YESNO, FUNCNAME$ + SPACE$(5) + "Windows Error")
                        SELECT CASE Continuable
                             CASE %IDYES
                                  RESUME NEXT
                             CASE %IDNO
                        END SELECT
                   CASE %NORESUME                                                             'Just let default handlers decide what to do
                   CASE %RESUME                                                               '<-- NOT recommended unless code added to correct how we got here in the 1st place
                        RESUME
                   CASE %RESUMENEXT                                                           'Resume code at next line of code
                        RESUME NEXT
              END SELECT
         END MACRO
    
    '******* Test functions to remove the need for GLOBALS, buy calling a function and Set or Get the value *******
         FUNCTION SetGetErrorCodes(ValueToSet AS LONG, ValueResults AS LONG, ResetValue AS LONG) AS LONG
              STATIC FunctionValue AS LONG                                                    'Static to hold current value
              SELECT CASE ResetValue                                                          'Decide whether to Set or to Get the current value
                   CASE %False, %UNKNOWN_VALUE                                                'If set to False, or -1 Then Get Current Value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
                   CASE = %TRUE                                                               'If set to True then Reset the Current Value
                        FunctionValue = ValueToSet                                            'Reset the value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
              END SELECT
              FUNCTION = %False                                                               'Return if Function Failed
         END FUNCTION
    
         FUNCTION SetGetLogErrors(ValueToSet AS LONG, ValueResults AS LONG, ResetValue AS LONG) AS LONG
              STATIC FunctionValue AS LONG                                                    'Static to hold current value
              SELECT CASE ResetValue                                                          'Decide whether to Set or to Get the current value
                   CASE %False, %UNKNOWN_VALUE                                                'If set to False, or -1 Then Get Current Value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
                   CASE = %TRUE                                                               'If set to True then Reset the Current Value
                        FunctionValue = ValueToSet                                            'Reset the value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
              END SELECT
              FUNCTION = %False                                                               'Return if Function Failed
         END FUNCTION
    
         FUNCTION SetGetLogFileNumber(ValueToSet AS LONG, ValueResults AS LONG, ResetValue AS LONG) AS LONG
              STATIC FunctionValue AS LONG                                                    'Static to hold current value
              SELECT CASE ResetValue                                                          'Decide whether to Set or to Get the current value
                   CASE %False, %UNKNOWN_VALUE                                                'If set to False, or -1 Then Get Current Value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
                   CASE = %TRUE                                                               'If set to True then Reset the Current Value
                        FunctionValue = ValueToSet                                            'Reset the value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
              END SELECT
              FUNCTION = %False                                                               'Return if Function Failed
         END FUNCTION
    
         FUNCTION SetGetSafeJump(ValueToSet AS LONG, ValueResults AS LONG, ResetValue AS LONG) AS LONG
              STATIC FunctionValue AS LONG                                                    'Static to hold current value
              SELECT CASE ResetValue                                                          'Decide whether to Set or to Get the current value
                   CASE %False, %UNKNOWN_VALUE                                                'If set to False, or -1 Then Get Current Value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
                   CASE = %TRUE                                                               'If set to True then Reset the Current Value
                        FunctionValue = ValueToSet                                            'Reset the value
                        ValueResults = FunctionValue                                          'Return Results as a parameter
              END SELECT
              FUNCTION = %False                                                               'Return if Function Failed
         END FUNCTION
    '--------------------------------------------------------------------------------
    '*** Now for the DOOZYYYYyyyy....Handling GPF's and other major fatal errors
    '--------------------------------------------------------------------------------
    '*************************************************************************************************************
    '*** ExceptionInfo is information that can be caught by 'ON ERROR' type of errors
    '*************************************************************************************************************
         FUNCTION ExceptionInfo(BYREF ErrorCode AS ErrorCodes) AS LONG
              STATIC TerminateInProcess AS LONG                                               'In case an error occurs while in the midst of ending my app
              LOCAL SafeReturnPoint AS LONG
    '*** Get the PB and Windows Error Descriptions (not caring which caused the error)
              ErrorCode.PbErrorDesc = ERROR$(ErrorCode.PbErrorValue)                          'Set the PB Error Description
              FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, ErrorCode.WinErrorValue, %NULL, ErrorCode.WinErrorDesc, SIZEOF(ErrorCode.WinErrorDesc), BYVAL %NULL     'Format the Windows Error Description
              ErrorCode.AppErrorDesc = ""                                                     'Clear the Application Specific Description
              ErrorCode.CodeModule = CALLSTK$(2)                                              'Figure out what function was the 'bad puppy' that caused the error
    '*** Revision check for if capable of logging the line Number that the error occurred on, or not
              SELECT CASE ErrorCode.LineLabelNumber
                   CASE ""
                        SELECT CASE %PB_REVISION
                             CASE > = &H900
                                  ErrorCode.LineLabelNumber = ERL$
                             CASE < &H900
                                  ErrorCode.LineLabelNumber = ""
                        END SELECT
                   CASE ELSE
              END SELECT
    '*** Check if logging errors (Commented out TRACE commands until fixed)
              SELECT CASE ErrorCode.LogError
                   CASE %FALSE
                   CASE %TRUE
                        TRACE ON
                        ErrorCode.Desc = ""
                        ErrorCode.Desc = "Error PB = " + TRIM$(STR$(ErrorCode.PbErrorValue))
                        ErrorCode.Desc = ErrorCode.Desc + SPACE$(5)
                        ErrorCode.Desc = ErrorCode.Desc + "Desc = " + ErrorCode.PbErrorDesc
                        REPLACE $CR WITH "" IN ErrorCode.Desc
                        IF ErrorCode.LogError THEN PRINT# ErrorCode.ErrorLogNumber, ErrorCode.Desc
                        ErrorCode.Desc = ""
                        ErrorCode.Desc = "Error Windows = " + TRIM$(STR$(ErrorCode.WinErrorValue))
                        ErrorCode.Desc = ErrorCode.Desc + SPACE$(5)
                        ErrorCode.Desc = ErrorCode.Desc + "Desc = " + ErrorCode.WinErrorDesc
                        REPLACE $CR WITH "" IN ErrorCode.Desc
                        IF ErrorCode.LogError THEN PRINT# ErrorCode.ErrorLogNumber, ErrorCode.Desc
                        SELECT CASE ErrorCode.PbErrorValue
                             CASE 0
                                  SELECT CASE ErrorCode.WinErrorValue
                                       CASE 0
                                            ErrorCode.AppErrorValue = 0
                                            ErrorCode.AppErrorDesc = "The operation completed successfully
                                       CASE ELSE
                                            ErrorCode.AppErrorValue = ErrorCode.WinErrorValue
                                            ErrorCode.AppErrorDesc = ErrorCode.WinErrorDesc
                                  END SELECT
                             CASE ELSE
                                  ErrorCode.AppErrorValue = ErrorCode.PbErrorValue
                                  ErrorCode.AppErrorDesc = ErrorCode.PbErrorDesc
                        END SELECT
                        ErrorCode.Desc = ""
                        ErrorCode.Desc = "Error App = " + TRIM$(STR$(ErrorCode.AppErrorValue))
                        ErrorCode.Desc = ErrorCode.Desc + SPACE$(5)
                        ErrorCode.Desc = ErrorCode.Desc + "Desc = " + ErrorCode.AppErrorDesc
                        REPLACE $CR WITH "" IN ErrorCode.Desc
                        'TRACE PRINT ErrorCode.Desc
                        IF ErrorCode.LogError THEN PRINT# ErrorCode.ErrorLogNumber, ErrorCode.Desc
                        ErrorCode.Desc = ""
                        ErrorCode.Desc = ErrorCode.Desc + SPACE$(5)
                        SELECT CASE ErrorCode.LineLabelNumber
                             CASE ""
                                  ErrorCode.Desc = ErrorCode.Desc + " Function: " + SPACE$(5) + ErrorCode.CodeModule
                             CASE ELSE
                                  ErrorCode.Desc = ErrorCode.Desc + " Function: " + SPACE$(5) + ErrorCode.CodeModule + SPACE$(5) + "at Mile-Marker:" + SPACE$(5) + ErrorCode.LineLabelNumber +  $CRLF
                        END SELECT
                        REPLACE $CR WITH "" IN ErrorCode.Desc
                        REPLACE $LF WITH "" IN ErrorCode.Desc
                        IF ErrorCode.LogError THEN PRINT# ErrorCode.ErrorLogNumber, ErrorCode.Desc
              END SELECT
              IF ErrorCode.LogError THEN PRINT# ErrorCode.ErrorLogNumber, $CRLF
         END FUNCTION
    
    '*************************************************************************************************************
    '*** ExceptionHandler is MUCH more difficult. (and Difficult to understand the documentation)
    '*************************************************************************************************************
    '*** <--- MEGA-IMPORTANT!!!!
    '***      According to http://www.debuginfo.com/articles/debugfilters.html
    '***      Custom filters for unhandled exceptions are not called at all when the application is running under debugger.
    '***      So this will not be called if using debugger
    '***
    '*************************************************************************************************************
         FUNCTION ExceptionHandler(BYREF lpEP AS EXCEPTION_POINTERS) AS LONG
              STATIC TerminateInProcess AS LONG
              LOCAL ErrorRecord AS EXCEPTION_RECORD POINTER
              LOCAL ErrorCode AS ErrorCodes POINTER
              LOCAL TempErrorCode AS LONG
              LOCAL Continuable AS LONG
              STATIC MostRecentError AS LONG
              LOCAL i AS LONG
              SetGetErrorCodes TempErrorCode, TempErrorCode, %UNKNOWN_VALUE                   'Since Windows NEEDS 'lpEP AS EXCEPTION_POINTERS' and only accepts 1 parameter, I had to find a work-around to Exceptions only wanting Exception Pointers
              ErrorCode = TempErrorCode
              SELECT CASE @ErrorCode.LineLabelNumber
                   CASE ""
                        SELECT CASE %PB_REVISION
                             CASE > = &H900
                                  @ErrorCode.LineLabelNumber = ERL$
                             CASE < &H900
                                  @ErrorCode.LineLabelNumber = ""
                        END SELECT
                   CASE ELSE
              END SELECT
              @ErrorCode.lpEP = VARPTR(lpEP)
              SELECT CASE TerminateInProcess                                                  'If App is unloading and a Error appears          '<--- To be developed later
                   CASE %TRUE
                   CASE %FALSE                                                                'If App is unloading and a Error appears          '<--- To be developed later
                        SELECT CASE @[email protected]                         'What Error caused me?
                             CASE 0
                             CASE ELSE
                                  ErrorRecord = @[email protected]             'Detect the actual exception record
                                  SELECT CASE @ErrorRecord.pExceptionRecord                   '<--- Array out of bounds if not checked for null pointer first
                                       CASE 0
                                       CASE ELSE
                                            DO UNTIL @ErrorRecord.pExceptionRecord = 0        'Gather the exception record(s)
                                                 CALL MoveMemory(@ErrorRecord, @ErrorRecord.pExceptionRecord, SIZEOF(ErrorRecord))
                                            LOOP
                                  END SELECT
    '*** Alert the log to 'FATAL' Errors that could occur
                                  @ErrorCode.Desc = ""
                                  SELECT CASE @ErrorRecord.ExceptionCode
                                       CASE 0              'No Error
                                            @ErrorCode.StringValue = "%NO_ERROR"
                                                 @ErrorCode.Desc = @ErrorCode.Desc  _
                                                                + "Error Windows = " + @ErrorCode.StringValue _
                                                                 + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                                + $CRLF + SPACE$(5) _
                                                                + " Desc = " + "The operation completed successfully"
                                       CASE %EXCEPTION_ACCESS_VIOLATION
                                            @ErrorCode.StringValue =  "%EXCEPTION_ACCESS_VIOLATION"
                                            @ErrorCode.Desc = @ErrorCode.Desc _
                                                           + "Error Windows = " + @ErrorCode.StringValue  _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5)
                                                           SELECT CASE @ErrorRecord.ExceptionInformation(0)
                                                                CASE 0
                                                                     @ErrorCode.Desc = @ErrorCode.Desc + " Desc = " + "The thread tried to READ from virtual address" _
                                                                     + STR$(@ErrorRecord.ExceptionInformation(1)) + " for which it does not have the appropriate access"
                                                                CASE 1
                                                                     @ErrorCode.Desc = @ErrorCode.Desc + " Desc = " + "The thread tried to WRITE to virtual address" _
                                                                     + STR$(@ErrorRecord.ExceptionInformation(1)) + " for which it does not have the appropriate access"
                                                                CASE 8
                                                                     @ErrorCode.Desc = @ErrorCode.Desc + " Desc = " + "The thread tried to cause a user-mode data execution prevention (DEP) violation at virtual address" _
                                                                     + STR$(@ErrorRecord.ExceptionInformation(1))
                                                           END SELECT
                                       CASE %EXCEPTION_ARRAY_BOUNDS_EXCEEDED
                                            @ErrorCode.StringValue = "%EXCEPTION_ARRAY_BOUNDS_EXCEEDED"
                                            @ErrorCode.Desc = @ErrorCode.Desc  _
                                                           + "Error Windows = " + @ErrorCode.StringValue  _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking."
                                       CASE %EXCEPTION_BREAKPOINT
                                            @ErrorCode.StringValue = "%EXCEPTION_BREAKPOINT"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "A breakpoint was encountered."
                                       CASE %EXCEPTION_DATATYPE_MISALIGNMENT
                                            @ErrorCode.StringValue = "%EXCEPTION_DATATYPE_MISALIGNMENT"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to READ or WRITE data that is misaligned on hardware that does not provide alignment." _
                                                                          + "For example, 16-bit values must be aligned on 2-byte boundaries"
                                       CASE %EXCEPTION_FLT_DENORMAL_OPERAND
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_DENORMAL_OPERAND"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "One of the operands in a floating-point operation is denormal." _
                                                                          + "A denormal value is one that is too small to represent as a standard floating-point value."
                                       CASE %EXCEPTION_FLT_DIVIDE_BY_ZERO
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_DIVIDE_BY_ZERO"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to divide a floating-point value by a floating-point divisor of zero."
                                       CASE %EXCEPTION_FLT_INEXACT_RESULT
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_INEXACT_RESULT"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The result of a floating-point operation cannot be represented exactly as a decimal fraction."
                                       CASE %EXCEPTION_FLT_INVALID_OPERATION
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_INVALID_OPERATION"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "This exception represents any floating-point exception not included in this list."
                                       CASE %EXCEPTION_FLT_OVERFLOW
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_OVERFLOW"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type."
                                       CASE %EXCEPTION_FLT_STACK_CHECK
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_STACK_CHECK"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The stack overflowed or underflowed as the result of a floating-point operation."
                                       CASE %EXCEPTION_FLT_UNDERFLOW
                                            @ErrorCode.StringValue = "%EXCEPTION_FLT_UNDERFLOW"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type."
                                       CASE %EXCEPTION_ILLEGAL_INSTRUCTION
                                            @ErrorCode.StringValue = "%EXCEPTION_ILLEGAL_INSTRUCTION"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to execute an invalid instruction."
                                       CASE %EXCEPTION_IN_PAGE_ERROR
                                            @ErrorCode.StringValue =  "%EXCEPTION_IN_PAGE_ERROR"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " +  @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5)
                                                           SELECT CASE @ErrorRecord.ExceptionInformation(0)
                                                                CASE 0
                                                                     @ErrorCode.Desc = @ErrorCode.Desc + " Desc = " + "The thread tried to READ from virtual address" _
                                                                     + STR$(@ErrorRecord.ExceptionInformation(1)) + " for which it does not have the appropriate access" _
                                                                     + $CRLF + "NTSTATUS = " + STR$(@ErrorRecord.ExceptionInformation(2))
                                                                CASE 1
                                                                     @ErrorCode.Desc = @ErrorCode.Desc + " Desc = " + "The thread tried to WRITE to virtual address" _
                                                                     + STR$(@ErrorRecord.ExceptionInformation(1)) + " for which it does not have the appropriate access" _
                                                                     + $CRLF + "NTSTATUS = " + STR$(@ErrorRecord.ExceptionInformation(2))
                                                                CASE 8
                                                                     @ErrorCode.Desc = @ErrorCode.Desc + " Desc = " + "The thread tried to cause a user-mode data execution prevention (DEP) violation at virtual address" _
                                                                     + STR$(@ErrorRecord.ExceptionInformation(1)) _
                                                                     + $CRLF + "NTSTATUS = " + STR$(@ErrorRecord.ExceptionInformation(2))
                                                           END SELECT
                                       CASE %EXCEPTION_INT_DIVIDE_BY_ZERO
                                            @ErrorCode.StringValue = "%EXCEPTION_INT_DIVIDE_BY_ZERO"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to divide an integer value by an integer divisor of zero."
                                       CASE %EXCEPTION_INT_OVERFLOW
                                            @ErrorCode.StringValue = "%EXCEPTION_INT_OVERFLOW"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The result of an integer operation caused a carry out of the most significant bit of the result."
                                       CASE %EXCEPTION_INVALID_DISPOSITION
                                            @ErrorCode.StringValue =  "%EXCEPTION_INVALID_DISPOSITION"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "An exception handler returned an invalid disposition to the exception dispatcher. " _
                                                                          + "Programmers using a high-level language such as C should never encounter this exception."
                                       CASE %EXCEPTION_NONCONTINUABLE_EXCEPTION
                                            @ErrorCode.StringValue =  "%EXCEPTION_NONCONTINUABLE_EXCEPTION"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to continue execution after a noncontinuable exception occurred."
                                       CASE %EXCEPTION_PRIV_INSTRUCTION
                                            @ErrorCode.StringValue =  "%EXCEPTION_PRIV_INSTRUCTION"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread tried to execute an instruction whose operation is not allowed in the current machine mode."
                                       CASE %EXCEPTION_SINGLE_STEP
                                            @ErrorCode.StringValue = "%EXCEPTION_SINGLE_STEP"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "A trace trap or other single-instruction mechanism signaled that one instruction has been executed."
                                       CASE %EXCEPTION_STACK_OVERFLOW
                                            @ErrorCode.StringValue = "%EXCEPTION_STACK_OVERFLOW"
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue   _
                                                            + " (" + STR$(@ErrorRecord.ExceptionCode) + ") "_
                                                           + $CRLF + SPACE$(5) _
                                                           + " Desc = " + "The thread used up its stack."
                                       CASE ELSE
                                            @ErrorCode.StringValue = "%Unhandled Error: "
                                            @ErrorCode.Desc = @ErrorCode.Desc   _
                                                           + "Error Windows = " + @ErrorCode.StringValue + STR$(@ErrorRecord.ExceptionCode)
                                       END SELECT
    '                                   'TRACE PRINT ErrorCode.Desc
                                       IF @ErrorCode.LogError THEN PRINT# @ErrorCode.ErrorLogNumber, @ErrorCode.Desc
                                       SELECT CASE @ErrorCode.LineLabelNumber
                                            CASE ""
                                                 IF @ErrorCode.LogError THEN PRINT# @ErrorCode.ErrorLogNumber, SPACE$(5) + "Function: " + SPACE$(5) + CALLSTK$(2)
                                            CASE ELSE
                                                 PRINT# @ErrorCode.ErrorLogNumber, "Function: " + SPACE$(5) + CALLSTK$(2) + SPACE$(5) + "at Mile-Marker:" + SPACE$(5) + @ErrorCode.LineLabelNumber +  $CRLF
                                       END SELECT
                                       @ErrorCode.Desc = "CallStack at Error" + $CRLF
                                       FOR i = CALLSTKCOUNT TO 1 STEP -1
                                            @ErrorCode.Desc = @ErrorCode.Desc + SPACE$(5) + CALLSTK$(i) + $CRLF
                                       NEXT i
                                       IF @ErrorCode.LogError THEN PRINT# @ErrorCode.ErrorLogNumber, @ErrorCode.Desc
                                       IF @ErrorCode.LogError THEN PRINT# @ErrorCode.ErrorLogNumber, $CRLF
                             END SELECT
    '*** Code for writing a crash-log, save opened documents etc...
    '*** In My case, this is where I decide whether to continue, or exit
    '>>> 1st attempt to RESUME NEXT I thought would be the following line to Resume Execution after the Exception
    '>>>      [email protected] = [email protected] + SIZEOF([email protected])
    '>>> Lo and Behold thanx to Paul Dixon's Post at http://www.powerbasic.com/support/pbforums/showthread.php?t=40575#post315530
    '>>> Led me to his post in the source code forum at http://www.powerbasic.com/support/pbforums/showthread.php?t=37821
    '>>> Although it is for PBCC and using Assembly code,
    '>>> I did some hunting and pecking and figured out that [email protected] = [email protected] + SIZEOF([email protected])
    '>>> Is the flag I need to set to 'Resume Next' (or any address I wish to jump to
                             SELECT CASE @ErrorCode.OverRideError
                                  CASE %RESUME
                                       FUNCTION = %EXCEPTION_CONTINUE_EXECUTION               'Ignore the Error and continue
                                  CASE %RESUMENEXT
                                       SELECT CASE IsBadCodePtr([email protected] + 1)      'SIZEOF([email protected])
                                            CASE 0              'Not an error
                                                 [email protected] = [email protected] + 1
                                                 FUNCTION = %EXCEPTION_CONTINUE_EXECUTION               'Ignore the Error and continue (Probably CRASH)
                                            CASE ELSE
                                                 SELECT CASE IsBadCodePtr([email protected])
                                                      CASE 0
                                                           FUNCTION = %EXCEPTION_CONTINUE_EXECUTION               'Ignore the Error and continue (Probably CRASH)
                                                      CASE ELSE
                                                           FUNCTION = %EXCEPTION_EXECUTE_HANDLER                  'See if another handler can fix, or crash anyways
                                                 END SELECT
                                       END SELECT
                                  CASE %UNKNOWN_VALUE                                         'Decide what to do after an error
                                       Continuable = MSGBOX("Fatal Error " + SPACE$(5) + @ErrorCode.StringValue + SPACE$(5) + "(" + STR$(@ErrorRecord.ExceptionCode) + ")" _
                                                      + $CR + "Function: " + SPACE$(5) + CALLSTK$(2) + $CR + $CR + "Ignore this error?", %MB_ICONERROR OR %MB_YESNO, FUNCNAME$ + SPACE$(5) + "Windows Error")
                                       SELECT CASE Continuable
                                            CASE %IDYES
    '**************************************** TEMPORARY TILL NEXT VERSION ****************************************
    LOCAL SafeJumpPoint AS LONG
    SetGetSafeJump(%UNKNOWN_VALUE, SafeJumpPoint, %UNKNOWN_VALUE)
    [email protected] = SafeJumpPoint
    FUNCTION = %EXCEPTION_CONTINUE_EXECUTION               'Ignore the Error and continue (Probably CRASH)
    EXIT FUNCTION
    '*************************************************************************************************************
                                                 FUNCTION = %EXCEPTION_CONTINUE_EXECUTION               'Ignore the Error and continue (Probably CRASH)
                                            CASE %IDNO
                                                 FUNCTION = %EXCEPTION_EXECUTE_HANDLER
                                       END SELECT
                                  CASE %NORESUME                                              'Let Windows handle the error
                                       FUNCTION = %EXCEPTION_EXECUTE_HANDLER
                                  CASE %CRASH
                                       FUNCTION = %EXCEPTION_CONTINUE_SEARCH                  'Similar to Let Windows handle the error, but if Windows can fix it, it will and then continue
                             END SELECT
                             MostRecentError = @ErrorRecord.ExceptionCode
                   END SELECT
         END FUNCTION
    #ENDIF
    DemoErrorHandling.bas
    Code:
    #DEBUG ERROR ON                                                                           'Set Compiler flag to not forgive me for errors like "Array out of Bounds"
    #COMPILE EXE                                                                              'Compile as executable
    #DIM ALL                                                                                  'Declare EVERYTHING!!! (do not let me get away with anything)
    #INCLUDE "Win32Api.inc"                                                                   'Include WinApi
    #INCLUDE "ErrorHandling.inc"                                                              'Include ErrorHandling
    
    '*** DECLARES (because I want to know everything is declared and I did not miss something
    DECLARE FUNCTION WINMAIN(BYVAL hInstance AS DWORD, BYVAL hPrevInst AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
    DECLARE FUNCTION DemoErrors ALIAS "DemoErrors"() AS LONG
    
    '*** Functions
    FUNCTION WINMAIN(BYVAL hInstance AS DWORD, BYVAL hPrevInst AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
         DemoErrors
    END FUNCTION
    
    FUNCTION DemoErrors ALIAS "DemoErrors"() EXPORT AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging                                                                              'Macro to turn on Error Handling / Logging
         SetGetLogErrors %TRUE, ErrorCode.LogError, %TRUE                                     'Set flag for logging errors
    '*** PowerBasic Errors
         DemoPbError                                                                          'Demo how PB Set Error code does not necessarily "RAISE" an Error Code
         DemoRaisePbError                                                                     'Demo how PB will "RAISE" an Error Code
    '*** Windows Errors
         DemoWinError                                                                         'Demo how Windows Set Error code does not necessarily "RAISE" an Error Code
    '*** Windows EXCEPTION ERRORS (The almighty "Windows has encountered an error in your app and has to close")
         DemoRaiseWinError                                                                    'Demo how Windows will "RAISE" an Error Code
    '*** Array Out of Bounds
         DemoArrayOutOfBounds                                                                 'Demo Array Out Of Bounds
    '*** UnderFlow (registers used for the calculation cannot hold the value)
         DemoUnderflow                                                                        'Demo "UnderFlow" (value too small for your data types)
    '*** OverFlow (Division by Zero)
         DemoOverflowDivisionByZero                                                           'Demo "OverFlow" (divide by zero) errors
    '*** CRASH!!!! (GPF)
         DemoGPF                                                                              'Demo the typical "Had an Error and has to close" that we are all aware of
    MSGBOX "Program Complete"                                                                 'Should NEVER get here because of GPF
         SetGetLogErrors %FALSE, ErrorCode.LogError, %TRUE                                    'Set flag for logging errors
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    '*** PB ERR    -    Error flag is set, but error is NOT raised,
    '***                So you have to check the value of ERR to see if there was an error
    FUNCTION DemoPbError()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
    DebugLine                                                                                 'Maro to insert line number (Disperce anywhere you think you want a landmark to home in on an error)
         ERR = 69                                                                             'Set Error Code (Error is not raised)
         PRINT# ErrorCode.ErrorLogNumber, STRING$(3, "*") + " <--- " + "ERR does NOT raise an error, it just sets a flag" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    '*** PB ERROR  -    Error flag is set, and error is raised,
    FUNCTION DemoRaisePbError()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         ErrorCode.OverRideError = %UNKNOWN_VALUE
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
    DebugLine
         ERROR 69                                                                             'Set Error Code (Error is raised, jump to error handler)
         PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "ERROR raises an error, and sets a flag" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    FUNCTION DemoWinError()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         ErrorCode.OverRideError = %RESUMENEXT
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
    DebugLine                                                                                 'Maro to insert line number (Disperce anywhere you think you want a landmark to home in on an error)
         SetLastError 5
         PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "SetLastError does NOT raise an error, it just merely setting a flag" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         SetLastErrorEx(69, %SLE_MINORERROR)
         PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "SetLastErrorEx does NOT raise an error, it just merely setting a flag" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    FUNCTION DemoRaiseWinError()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         ErrorCode.OverRideError = %RESUMENEXT
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
    DebugLine
         RaiseException %NULL, %NULL, %NULL, %NULL                                            'Bogus Fatal Error for Demo (or not fatal since I have control)
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "Continued from 1st error that was raised" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
    '*** Did this twice just to show how you can continue after a Crash (GPF)
    DebugLine
         RaiseException %EXCEPTION_ACCESS_VIOLATION, %NULL, %NULL, %NULL                      'Bogus Fatal Error for Demo (or not fatal since I have control)
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "Continued from 2nd error that was raised" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    FUNCTION DemoArrayOutOfBounds()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         ErrorCode.OverRideError = %UNKNOWN_VALUE
         DIM MyArrayOutOfBounds(0) AS LONG
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
    DebugLine
         MyArrayOutOfBounds(1) = 5
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "Continued from 1st error that was raised" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
    DebugLine
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
    DebugLine
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    FUNCTION DemoOverflowDivisionByZero()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         SetGetLogErrors %UNKNOWN_VALUE, ErrorCode.LogError, %UNKNOWN_VALUE                   'Get flag for logging errors
         ErrorCode.OverRideError = %UNKNOWN_VALUE                                             'Continue after an error?        '<--- Do NOTTTTT change this to %RESUME or you will be stuck in a logging loop
         LOCAL MyOverFlow AS LONG
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
         MyOverFlow = 4 \ 0
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "MyOverFlow = 4 \ 0 Results in Pb protecting me (no error)" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         LOCAL a,b,c AS LONG
         LOCAL x,y,z AS CURRENCY
    DebugLine                                                                                 'Maro to insert line number (Disperce anywhere you think you want a landmark to home in on an error)
         x=0.0
         y=1.0
         z=y/x                                                                                'Floating Point Division (/) by zero, I am protected by PB
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "Floating Point DivByZero: z = y/x Results in PB protecting me (no error)" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, $LF
         a=0
         b=1
         c=b\a                                                                                'Integer Division (\) by zero (error)          '<--- To be investigated
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "Integer DivByZero: c = b\a Results in allowing an error" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    FUNCTION DemoUnderflow()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         SetGetLogErrors %UNKNOWN_VALUE, ErrorCode.LogError, %UNKNOWN_VALUE                   'Get flag for logging errors
         ErrorCode.OverRideError = %UNKNOWN_VALUE                                             'Continue after an error?        '<--- Do NOTTTTT change this to %RESUME or you will be stuck in a logging loop
         LOCAL B AS BYTE
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
         DO WHILE B  < 256
              B = B + 1
              IF B + 1 = 256 THEN EXIT DO
         LOOP
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "B + 1 to overflow, PB protecting me (no error)" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         B = 255 + 1
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "B + 1 to overflow, PB protecting me (no error)" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
    DebugLine     PRINT# ErrorCode.ErrorLogNumber,      STRING$(3, "*") + " <--- " + "B = 255 + 1 to overflow, PB protecting me (no error)" + " ---> "+ STRING$(3, "*")     'Notes to print to Log File
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    
    FUNCTION DemoGPF()AS LONG
         OnError                                                                              'Macro to turn on Error Handling / Logging
         SetGetLogErrors %UNKNOWN_VALUE, ErrorCode.LogError, %UNKNOWN_VALUE                   'Get flag for logging errors
    '*** Let Windows Crash
         MSGBOX "I will now perform a fatal error, and not recover from it", %MB_ICONINFORMATION, "Fatal Error"
         ErrorCode.OverRideError = %CRASH
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + FUNCNAME$ + SPACE$(5) + STRING$(40, "-")
         RaiseException %NULL, %NULL, %NULL, %NULL                                            'Bogus Fatal Error for Demo (or not fatal since I have control)
         PRINT# ErrorCode.ErrorLogNumber, "I continued from a crash"                          'Should never get here
         PRINT# ErrorCode.ErrorLogNumber, STRING$(40, "-") + SPACE$(5) + "END " + FUNCNAME$ + SPACE$(5) + STRING$(40, "-") + $CRLF + $CRLF
         HandleErrors                                                                         'Macro to turn off Error Handling / Logging
    END FUNCTION
    Just keep ignoring the errors that are created in the demo, and check out the log created for each of those errors.

    Discussion can be found here
    Last edited by Cliff Nichols; 28 Jun 2009, 01:13 PM.
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "
Working...
X