Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

? Where Find a Specific Error Handler

Status
Not open for further replies.

Pontelo

Programmer
Dec 18, 2001
80
BR
Does someone have or knows where to find an Error Treatment
routine that capture and try to treat any kind of error,
and besides, shows function/proc where error fires and
other usefull information for we detect and fix bugs ?
Thanks in advance.
 
hi

Apologies but I don't know your level of expertise with Delphi but have you had a look at TRY..EXCEPT and TRY..FINALLY constructs?

You could develop these to write errors to a log,

eg

procedure TForm1.Proc1;
begin
TRY
:
EXCEPT
on e:exception do
LogError ('TForm1.Proc1 : '+ e.message);
END;
end;

:
:
procedure LogError(msg : string);
begin
//NOTE, you need to initialise a file before calling this routine
writeln(msg);
:
end;

lou


 
My level is still low. I'm an old clipper programmer.
I´ve seen try..except..finally. Let me try explain (excuse grammar) : In our clipper system we have a lot of customer. Every one is in a different release. I developed a default screen (called System Alert) and every exception is caught and treated in that routine. So, when an exception raises, the routine log it to a file, and open a "form" with fields that describes : The bug raises in routine XYZ() ( line XXX ), that was called by routine ABC() (line XXX) (six calling level), the error code is XXX, the description of that code, the file involved is XXX.DBF (or the operator is X), and others informations. This makes system standardized in a way that your customers are soon familiarized. They print the screen or calls you by phone, describe the problem and you, very quickly, diagnose the problem and offer a workaround (when possible) for that moment.That system has 250,000 lines of code and sometimes is hard you get the point of problem if you don´t have a tracker.

 
This is actually fairly easy to do in your code. In your main form, declare a function called ApplicationError like this:
procedure ApplicationError(Sender: TObject; E: Exception);

In the OnCreate event handler of the Main Form put the following:
application.OnException := ApplicationError;

You then create the ApplicationError code to create your log file.

-D
 
Hilfy
I already did it. But in this moment my system show a poor
form with very little information, in relation to clipper, as i mentioned above. The question is : what functions, procedures, whatever, we have to keep track from callers (kind of stack pointer) ? What more information can we get besides a MessageString of the bug ?
Thanks !

 
I know there's a way to do this using interface information, but I'm not sure how to go about it.

One possible way to get the information you need would be to create a global variable where you would store the name of the function or procedure you're in. This is a lot of overhead, though, as you would have to set it every time you enter a function/procedure and then reset it back to what it was before you leave the function or procedure.

-D
 
Hilfy
Thank You again. I´ve seen doing some tests with vars. and functions like GetLastError, ExceptAddr, ErrorAddr among others but i still have no success. I´ll post a message since I get satisfied with this problem. Your idea is a question to be analyzed ´cause having no other mechanisms this must be used (even causing overhead).
But let me ask one more question : In Delphi what is the better place to declare global variables ? Is a case to create an object and face all vars. as properties of this object ? In clipper i have one .prg where i declare all variables and so is easy to share among any modules and systems only including that module in systems.
 
Actually, it's not Interfaces you'll need, but Runtime Type Information (RTTI). I saw this done in a class several years ago, but haven't ever used it.

In the meantime, I would create an object that holds your global information. Make it Public or Protected in your main form and put the main form's file name in a Uses clause at the top of the Implementation section of each of your other units (if you put it in the Interface section, you'll get a "circular reference" error when you try to compile.)

You can define the object in either the Main Form (not recommended) or in its own unit. It might look something like this:
Code:
Type
  TFunctionInfo = Class(TObject)
    fFunctionName: String;
    slPreviousFuncs: TStringList;  //stack to keep previous function names in
    //...any other info you want to keep track of
  private
    function Get_FunctionName: String;
    function Set_FunctionName(value: String): String;
  published
    Constructor Create;
    Destructor Destroy;
  public
    function ResetFunctionName: String;
    function GetFunctionStack: String;
    property FunctionName: String read Get_FunctionName write Set_FunctionName;
    
end;

Implementation

constructor TFunctionInfo.Create;
begin
  inherited;
  fFunctionName := '';
  slPreviousFuncs := TStringList.Create;
end;    

destructor TFunctionInfo.Destroy;
begin
  //do any clean up you need to do...
  FreeAndNil(slPreviousFuncs);
  inherited;
end;

function TFunctionInfo.Get_FunctionName: String;
begin
  //do anything else you need to do
  result := fFunctionName;
end;

function TFunctionInfo.Set_FunctionName(value: String); 
begin
  slPreviousFuncs.Add(fFunctionName); //save the old one
  fFunctionName := value;
end;

function TFunctionInfo.ResetFunctionName: String;
begin
  fFunctionName := slPreviousFuncs[slPreviousFuncs.Count - 1];  //get the previous function name
  slPreviousFuncs.Delete(slPreviousFuncs.Count - 1);  //Delete what we just reset to.
end;

funcion TFunctionInfo.GetFunctionStack: String;
begin
  result := slPreviousFuncs.CommaText;
  //return a comma-delimited string of the previous function names.
end;
You would create this in the Main Form, say as an object called FInfo:

FInfo := TFunctionInfo.Create;

Destroy it in the OnClose event of the main form:

FreeAndNil(FInfo);

At the top of every function you would put:

MainForm.FInfo.FunctionName := <name of function>

Reset at the end of each function:

MainForm.FInfo.ResetFunctionName;

In your error handler (assumed to be in your main form...), you can get the list of all of the functions that have been called to get you to a specific point by:
FInfo.GetFunctionStack;

This is a bare-bones sort of thing that you can adapt to your needs.

-D
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top