11

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)

Heinrich Ulbricht
  • 10,064
  • 4
  • 54
  • 85

4 Answers4

17

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
  • 7,670
  • 28
  • 36
  • 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 Apr 13 '10 at 11:25
  • Ok SysUtils.pas already assigns `RaiseExceptObjProc`. Maybe this should indeed be called by my handler. – Heinrich Ulbricht Apr 13 '10 at 11:51
  • hey can you please provide an example? :) – PresleyDias Jul 17 '12 at 07:12
  • For code sample using this function pointer, take a look at http://stackoverflow.com/a/6415902/458259 - for Delphi 5 up to XE4, on Win32 and Win64 platforms. – Arnaud Bouchez Aug 30 '13 at 06:28
  • Whilst this works well, one issue I've discovered with it is that it will trap all exceptions before and regardless of how or if they're handled. This can cause issues with exceptions which are deliberately eaten/swallowed by your code because failure is anticipated. I use this hooking method to trap and log all exceptions within a service application and have not yet found a way to suppress such exceptions. – Toby Groves Mar 19 '15 at 17:27
9

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
  • 7,214
  • 2
  • 32
  • 52
  • This traps exceptions at the win32 level, Dmitry Arefiev's solution but me more what you expected. – Remko Apr 13 '10 at 11:01
  • 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 Apr 13 '10 at 11:28
  • +1 Because I just needed this API call in order to support older version of Delphi (e.g. Delphi 6-7), in which RaiseExceptObjProc is not existing. – Arnaud Bouchez Mar 30 '11 at 14:55
2

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

mj2008
  • 6,647
  • 2
  • 38
  • 56
  • @Arafangion I'd start by reading the documentation for madExcept, which will tell you all you need to know. In essence, you create an exception handler (try/except) and then pass the exception object to HandleException for processing by madExcept, which does the magic. – mj2008 Sep 04 '12 at 07:49
  • The documentation is vague about how to handle the *uncaught* exceptions, though, particularly when you start caring about SEH exception handling. – Arafangion Sep 04 '12 at 16:28
1

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
  • 5,485
  • 1
  • 25
  • 35