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 ;)")