Navigation: Language Reference > App C - PROP: Runtime Properties > Complete Property List >====== PROP:LastChanceHook ====== | |
This is a SYSTEM read/write property (returning a LONG) that allows you to specify your own function that will be invoked if an exception has occurred. The hook function allows you to display information about the exception and choose one of the following actions:
·Continue execution of the thread where the exception occurred (unless the exception is fatal).
·Stop the thread (or the entire process if the exception occurred in the main process thread) without invoking the RTL's (runtime library) internal exception handler.
·Invoke the RTL's internal exception handler.
This allows you to catch an exception, and if it is non-fatal you can allow your end users to continue executing your program even when an exception has occurred in one of its threads.
The RTL handler shows information about the exception and asks for one of the following actions:
·Stop the thread where the exception occurred.
·Stop the entire process.
·Invoke the system debugger
·Generate a debug event if the program is already running under the debugger.
The action is dependent on the thread with the exception, whether the program is running under the debugger, etc.
PROP:LastChanceHook also allows the developer to set the exit code (error level) returned by the program to the OS on its termination, without the need to terminate the program immediately as is done when using the HALT statement.
Implementation:
Your function, which you assign to the SYSTEM{PROP:LastChanceHook} property must use the following prototype:
HookProc (*ICWExceptionInfo),LONG
The ICWExceptionInfo Parameter is an interface declared in CWEXCPT.INT, which is found in your LIBSRC folder.
The result returned by the hooked function is evaluated as follows:
·If the result is equal to 0, the RTL executes its own internal exception handler dialog to show information about the exception and subsequently perform the action chosen by the end user.
·If a positive number is returned, the RTL stops the thread (or the entire process if the exception occurred in the main process thread) without invoking the RTL exception handler
·If a negative number is returned, the program will try to continue from the point of the exception. Note, if the exception is fatal, this result is ignored and treated as equal to zero (0).
Example:
PROGRAM INCLUDE(’CWEXCPT.INT’),ONCE MAP Test (LONG,LONG) Hook (*ICWExceptionInfo),LONG HEX (LONG),STRING,PRIVATE MODULE(") MessageBox(UNSIGNED, CONST *CSTRING, CONST *CSTRING, UNSIGNED)| ,SIGNED,PROC,PASCAL,NAME(’MessageBoxA’) END END MB_ICONHAND EQUATE(00000010h) CODE SYSTEM{PROP:LastChanceHook} = ADDRESS(Hook) Test (10, 0) !intentionally causes an exception RETURN
In this example the procedure named Hook is assigned as our exception handler. That's the only procedure we are concerned with, the others are just there to help to make the example work by 1) causing an exception and 2) informing the user about the exception.
Next we have:
Hook PROCEDURE(*ICWExceptionInfo info) S CSTRING(1024) Caption CSTRING(256) CODE IF info &= NULL RETURN 0 END Caption = 'Exception ' & HEX (info.ExceptionCode()) & ' at ' & HEX (info.ExceptionAddress()) S ='Registers' & | '<13,10>EAX= ' & HEX (info.Register (i386_Register:Reg32_EAX)) & | ' EBX= ' & HEX (info.Register (i386_Register:Reg32_EBX)) & | ' ECX= ' & HEX (info.Register (i386_Register:Reg32_ECX)) & | ' EDX= ' & HEX (info.Register (i386_Register:Reg32_EDX)) & | '<13,10>ESI= ' & HEX (info.Register (i386_Register:Reg32_ESI)) & | ' EDI= ' & HEX (info.Register (i386_Register:Reg32_EDI)) & | ' ESP= ' & HEX (info.Register (i386_Register:Reg32_ESP)) & | ' EBP= ' & HEX (info.Register (i386_Register:Reg32_EBP)) & | '<13,10,13,10>Current thread is being terminated ' MessageBox(0, S, Caption, MB_ICONHAND) RETURN 1 !a positive value signals the RTL to kill the thread ! ***************************** Test PROCEDURE (LONG a, LONG b) CODE a %= b ! ***************************** HEX PROCEDURE (LONG A) i UNSIGNED,AUTO S STRING(8),AUTO DIGITS STRING(’0123456789ABCDEF’),STATIC CODE i = SIZE(S) LOOP WHILE i <> 0 S [i] = DIGITS [BAND (A, 0Fh) + 1] A = BSHIFT (A, -4) i -= 1 END RETURN S
These first two lines of code assign our exception handler function and then call the Test procedure that raises an exception:
SYSTEM{PROP:LastChanceHook} = ADDRESS (Hook) Test (10, 0) ! causes an exception
The exception is trapped and we show the result in an API MessageBox.
Our Hook PROCEDURE(*ICWExceptionInfo info) uses the methods in the interface to show the exception code, its address, and the values of the registers at the time of the exception.
In our example our Hook PROCEDURE executes a RETURN 1 and since we are running on the main thread, then immediately after the MessageBox is displayed and the user presses the OK button the program itself is terminated.
Conceptual Example:
PROGRAM INCLUDE('CWEXCPT.INT'),ONCE MAP MyHandler(*ICWExceptionInfo),LONG BadCode() MODULE('') SLEEP(LONG),PASCAL END END badPtr &LONG temp LONG oldHandler LONG continue BOOL(FALSE) CODE RESUME(START(BadCode)) LOOP WHILE NOT continue SLEEP(100) END badPtr &= NULL badPtr = 0 RETURN BadCode PROCEDURE() CODE oldHandler = SYSTEM{PROP:LastChanceHook} !Read address of oldhandler SYSTEM{PROP:LastChanceHook} = ADDRESS(MyHandler)!Call new handler badPtr = 0 RETURN MyHandler PROCEDURE(*ICWExceptionInfo info) CODE SYSTEM{PROP:LastChanceHook} = oldHandler MESSAGE('Someone did something naughty') continue = TRUE RETURN 1