Requires Windows XP or newer, 32bit and 64bit PureBasic.
Code: Select all
;---[ Try Catch EndTry ]----------------------------------------------------
;
; Structured Exception Handling for WinXP+, PureBasic/Windows 32bit + 64bit
;
; by Danilo, May 2012
;
Import "kernel32.lib"
    AddVectoredExceptionHandler(FirstHandler.l, *VectoredHandler)
    RemoveVectoredExceptionHandler(*Handler)
EndImport
Structure ExceptionHandlerStack
    catchAddress.i
    oldHandler.i
    StackPointer.i
EndStructure
Threaded NewList ExceptionHandlerList.ExceptionHandlerStack()
Threaded CurrentExceptionInfo.EXCEPTION_POINTERS
Procedure.l UnhandledExceptionFilter(*ExceptionInfo.EXCEPTION_POINTERS)
    CopyStructure(*ExceptionInfo,@CurrentExceptionInfo,EXCEPTION_POINTERS)
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        *ExceptionInfo\ContextRecord\Eip = ExceptionHandlerList()\catchAddress
        *ExceptionInfo\ContextRecord\Esp = ExceptionHandlerList()\StackPointer
    CompilerElse
        *ExceptionInfo\ContextRecord\Rip = ExceptionHandlerList()\catchAddress
        *ExceptionInfo\ContextRecord\Rsp = ExceptionHandlerList()\StackPointer
    CompilerEndIf
    ;SetUnhandledExceptionFilter_( ExceptionHandlerList()\oldHandler )
    RemoveVectoredExceptionHandler( ExceptionHandlerList()\oldHandler )
    DeleteElement( ExceptionHandlerList() )
    ProcedureReturn $ffffffff
EndProcedure
Procedure AddExceptionHandler(*catch,StackPointer.i)
    If AddElement( ExceptionHandlerList() )
        ;ExceptionHandlerList()\oldHandler   = SetUnhandledExceptionFilter_(@UnhandledExceptionFilter()) ; Win2000pro+ 32bit
        ExceptionHandlerList()\oldHandler   = AddVectoredExceptionHandler(1,@UnhandledExceptionFilter()) ; XP+
        ExceptionHandlerList()\catchAddress = *catch
        ExceptionHandlerList()\StackPointer = StackPointer
    EndIf
EndProcedure
Global AddExceptionHandler.i = @AddExceptionHandler()
! macro __try {
!    local label1, label2, label3
!    handler_label equ label1
!    handler_end_label equ label2
!    end_try_label equ label3
! }
Macro Try
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !__try
    ! push esp
    ! push handler_label
    ! call [v_AddExceptionHandler]
    CompilerElse
    !__try
    ! mov qword rdx, rsp
    ! mov qword rcx, handler_label
    ! call qword [v_AddExceptionHandler]
    CompilerEndIf
EndMacro
Macro Catch
    !jmp end_try_label
    !handler_label:
EndMacro
Macro EndTry
    !end_try_label:
    ! restore handler_label
    ! restore end_try_label
    ! restore handler_end_label
EndMacro
;---------------------------------------------------------------------------
CompilerIf #PB_Compiler_Debugger
    ;CompilerError "please disable debugger"
    DisableDebugger
CompilerEndIf
Procedure a()
    Try
        Try
           a = 0
           b = 4/a ; 4/0 = division by zero exception
        Catch
           MessageRequester("INFO","Catched inner exception")
        EndTry
    
        PokeI(0,1234) ; Poke something to address 0
    
    Catch
       MessageRequester("INFO","Catched outer exception")
    EndTry
EndProcedure
Procedure b()
    !push 1234 ; change stack = crash
EndProcedure
a()
Try
    b()
Catch
    MessageRequester("INFO","Catched stack corruption")
EndTry
MessageRequester("INFO","OK, still alive ;)")




