Page 1 of 2

[Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Tue May 08, 2012 8:43 pm
by Danilo
Simple Macros for catching program exceptions and continue the program.

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 ;)")
The variable "CurrentExceptionInfo" contains the exception informations.

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 9:34 am
by dige
Thank you Danilo. It it the same mechanism like the POSL TryCatch Lib?

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 9:41 am
by Danilo
dige wrote:Thank you Danilo. It it the same mechanism like the POSL TryCatch Lib?
I don't know. Wasn't aware there was already a Try..Catch somewhere.

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 3:23 pm
by Little John
Great! Thank you, Danilo.

Regards, Little John

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 3:54 pm
by skywalk
Very cool Danilo, can't wait to "Try" this. :wink:

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 4:14 pm
by Kiffi
Thanks Danilo!

Works under 32 Bit. But under 64 Bit:

Image

Did i missed something?

Greetings ... Kiffi

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 4:52 pm
by ts-soft
Kiffi wrote:Did i missed something?

Greetings ... Kiffi
I think, you have enabled the Debugger :wink:

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 5:35 pm
by Danilo
Kiffi wrote:Thanks Danilo!

Works under 32 Bit. But under 64 Bit:

Image

Did i missed something?

Greetings ... Kiffi
I wondered about this too. I made a small mistake: First argument of AddVectoredExceptionHandler()
has to be nonzero to become the first handler. I changed it in the code above, thanks.

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Wed May 09, 2012 7:16 pm
by Kiffi
@Danilo: Works perfect! Thanks a lot! Image

Greetings ... Kiffi

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Fri May 11, 2012 3:28 am
by RichAlgeni
Would this replace OnErrorCall()?

Coming from a background that had no Try-Catch, could you give me a quick heads up to someone would utilize this? Would it be useful in using functions over a network, where it's possible for the network connection to be dropped, and this procedure might gracefully handle that situation?

Thanks!

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Sat May 12, 2012 1:45 pm
by dige
@Danilo: Duno why, but using try / catch for CatchImage and LoadImage, makes the program unstable...
I use the OnError Lib too. May be there are now some side effects?

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Fri May 25, 2012 8:56 pm
by TeraByte
Thank you Danilo for your excellent code! :D

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Fri May 25, 2012 9:11 pm
by Little John
Danilo wrote:Simple Macros for catching program exceptions and continue the program.

Requires Windows XP or newer
Danilo, what happens if I use this code in a compiled EXE program, and someone runs that program on Windows 2000? OK, your code will probably not catch exceptions then ... but can it cause any problems on Windows 2000?

Regards, LIttle John

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Fri May 25, 2012 9:32 pm
by ts-soft
@Little John
If imported functions not available, so your exe will not start!

I think, dynamic load of functions should help.

Re: [Windows XP+] Try .. Catch .. EndTry - Error Handling

Posted: Sat May 26, 2012 6:27 am
by Danilo
Little John wrote:Danilo, what happens if I use this code in a compiled EXE program, and someone runs that program on Windows 2000? OK, your code will probably not catch exceptions then ... but can it cause any problems on Windows 2000?

Regards, LIttle John
As ts-soft said, the exe will not start because the functions imports are not found in kernel32.lib

If you change the 2 out-commented lines, it should work with Win95+, but only with 32bit PureBasic.
First 64bit Windows was WindowsXP, right?

So for 32bit only and Win95+ use this version:

Code: Select all

;---[ Try Catch EndTry ]----------------------------------------------------
;
; Structured Exception Handling for Win95+, PureBasic/Windows 32bit only
;
; by Danilo, May 2012
;
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
        CompilerError "This version of Try/Catch does not support 64bit PureBasic"
    CompilerEndIf

    SetUnhandledExceptionFilter_( ExceptionHandlerList()\oldHandler )

    DeleteElement( ExceptionHandlerList() )
    ProcedureReturn $ffffffff

EndProcedure

Procedure AddExceptionHandler(*catch,StackPointer.i)
    If AddElement( ExceptionHandlerList() )
        ExceptionHandlerList()\oldHandler   = SetUnhandledExceptionFilter_(@UnhandledExceptionFilter()) ; Win95+ 32bit
        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 ;)")
dige wrote:I use the OnError Lib too. May be there are now some side effects?
Yes, I think the OnError Lib uses the same functions internally.