开发者

Can Delphi tell me the name of the routine that threw an exception?

I know how to catch exceptions in delphi (try..except/finally and e.message) but I want to know if there exists an exception handling mechanism which can开发者_JAVA百科 raise the exception and also the name of the routine which raised it. by example

procedure/function bla();//this can be in a unit/class
begin
 code....
 an error  is raised here -> inside or not of an try-except/finally block 
end;

and I'll receive an message/object/anything that indicates me that error 'x' was raised in 'bla'.

I know about madexcept, there is another way to catch exceptions as they do?

I'm using Delphi 7. Solution may be applicable to other Delphi version also.


You can use the ProcByLevel function from the JclDebug.pas unit wich is part of the JCL library.

before to use you must activate the option 'Insert JDBG data into the binary' from the Ide Menu tools->jcl Options.

Can Delphi tell me the name of the routine that threw an exception?

and then you can use it in this way

Uses
 JclDebug;

procedure TForm18.Button1Click(Sender: TObject);
begin
    try

       raise  Exception.Create('Hello from '+ProcByLevel(0));
    except
         on e : Exception do
         ShowMessage(e.Message);
    end;
end;

and the result is something like this

Can Delphi tell me the name of the routine that threw an exception?


EurekaLog is also an excellent tool, on par with MadExcept.

If you have EurekaLog:

uses
  EDebugInfo;

procedure TMyObject.SomeMethod();
begin
  Writeln('my name is: ' + __FUNCTION__); 
end;

There is also __FILE__, __MODULE__, __UNIT__, __LINE__, as well as a generic GetLocationInfoStr function.

However:

  1. It will only work if you are compiling with some debug information (and the corresponding debug info provider is enabled):
  • EurekaLog has its own debug info format, which can be optionally compressed (which is actually not recomended, as you will spend more memory and CPU).
  • It also supports JCL/JEDI, Synopse/MAB, as well as .map, .tds/TD32, .dbg, .pdb.
  1. It is NOT a constant. The name will be looked up dynamically, so it have some run-time costs.


Libraries like MadExcept adds metadata to the application so it can map an address to a unit and function name.

Delphi doesn't do that automatically and does not provide a mean to do directly that, it just provides the address which raised the exception.

Some alternatives to do what you want are:

  • FastMM
  • Jedi
  • MadExcept

With those you can get a snapshot of the call stack when an exception happens.


Also look at JCLDebug's JCLLastExceptStackListToStrings() which gives you a nice stack dump of the point of exception.

And like TheNewbie noted: you get this by setting TApplication.OnException to be the address of your error handler.


No, Delphi doesn't have any built-in "get the name of the current function" feature. MadExcept or similar products are probably the best way to get meaningful names in error reports.


MadExcept is the best solution I've found so far, of course, but if your needs are not too fancy and your project is commercial, then you should check Project JEDI's JCL (especially JclDebug.pas). There you'll find many helpful routines. It supports .MAP files, TurboDebugger symbols, etc. Also, with it you can embed the debug info (as with MadExcept).

You might also want to look into TApplication.OnException (and related).


As others have stated...JCL has some nice features...

In your application...You need to set up some info to get the necessary Stack Frame for the Hook...
Project-->Compiler->Stack Frames...I also have all the Debugging checked and add the following...Project->Options->Linker->Map file(Select Detailed)/Include TD32 debug Info

In my Logger unit...I have this...You'll have to have your own TLogger...that saves the info for you...

use
  JclDebug, JclHookExcept;


procedure HookGlobalException(ExceptObj: TObject; ExceptAddr: Pointer; OSException: Boolean);
var
  a_List: TStringList;
  a_Error: string;
begin
  if Assigned(TLogger._Instance) then
  begin
    a_List := TStringList.Create;
    try
      a_List.Add(cStar);
      a_Error := Exception(ExceptObj).Message;
      a_List.Add(Format('{ Exception - %s }', [a_Error]));
      JclLastExceptStackListToStrings(a_List, False, True, True, False);
      a_List.Add(cStar);
      // save the error with stack log to file
      TLogger._Instance.AddError(a_List);
    finally
      a_List.Free;
      Raise Exception.Create(a_Error);
    end;
  end;
end;

initialization
  Lock := TCriticalSection.Create;
  Include(JclStackTrackingOptions, stTraceAllExceptions);
  Include(JclStackTrackingOptions, stRawMode);

  // Initialize Exception tracking
  JclStartExceptionTracking;

  JclAddExceptNotifier(HookGlobalException, npFirstChain);
  JclHookExceptions;

finalization
  JclUnhookExceptions;
  JclStopExceptionTracking;
  Lock.Free;

end.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜