views:

262

answers:

4

Hi,

my code is fairly well covered with exception handling (try..except). Some exceptions are not expected to happen and some exceptions happen fairly often, which is expected and ok. Now I want to add some automated tests for this code. It would be good to know how many exceptions happened during execution, so I can later see if the expected number was raised or anything unexpected happened. I don't want to clutter every exception handling block with debug code, so my question is:

Is there a way to install some kind of global exception handler which sits right before all other exception handling blocks? I am searching for a central place to log these exceptions.

Thanks for any suggestions!

(And if this matters: it is Delphi 2009)

A: 

JCL has it's own exception dialog. Just add this dialog to your project, it will handle all unexpected exceptions. Detailed info located in this JCL folder: jcl\experts\debug. There is also howto text file which step by step describes how to use it.

Linas
The OP is looking for hooking into *handled* exceptions, too.
DR
+2  A: 

I think you can use the AddVectoredExceptionHandler API function.

Here is a small sample on how to use:

var
  f : TFileStream;

    function VectoredHandler(ExceptionInfo : PEXCEPTION_POINTERS): LongInt; stdcall;
    var 
      s : String;
    begin
      S := Format('Exception code %x address %p'#10#13, [ExceptionInfo^.ExceptionRecord^.ExceptionCode,
       ExceptionInfo^.ExceptionRecord^.ExceptionAddress]);
       f.WriteBuffer(PChar(s)^, Length(s) * sizeof(wchar));
       FlushFileBuffers(f.Handle);
      OutputDebugString(PChar(Format('ExceptionCode: %x', [ExceptionInfo^.ExceptionRecord^.ExceptionCode])));
      result := EXCEPTION_CONTINUE_SEARCH ;
    end;


    initialization
      AddVectoredExceptionHandler(0, VectoredHandler);
Remko
This traps exceptions at the win32 level, Dmitry Arefiev's solution but me more what you expected.
Remko
Thanks for pointing to this functions, I think this could come handy for somebody doing pure Win32. Dmitry's solution was just easier in my case.
Heinrich Ulbricht
+7  A: 

You can do the following:

  • preserve the value of System.RaiseExceptObjProc variable, which in normal Delphi app is pointing to SysUtils.RaiseExceptObject
  • create your own "RaiseExceptObject" proc and assign it to the RaiseExceptObjProc variable
  • in your own "RaiseExceptObject" proc you can do what you want, then call saved RaiseExceptObjProc value

For details, see above variable and procedure declarations.

da-soft
Woohoo! That's it :) Thanks very much for this tip! And for the record: 1) Signature of `RaiseExceptObjProc`: `procedure(P: PExceptionRecord)` 2) it seems I don't have to call the old `RaiseExceptObjProc` in my handler 3) I read somewhere this is available since Delphi 2009 (good for me), but I am not sure about this
Heinrich Ulbricht
Ok SysUtils.pas already assigns `RaiseExceptObjProc`. Maybe this should indeed be called by my handler.
Heinrich Ulbricht
A: 

You could add a custom handler to madExcept which would then allow you to get a full stack trace, but also carry on.

mj2008