Sunteți pe pagina 1din 6

Answer:

To have a proper control of the exceptions in an Application, a new class is cre


ated - ECustomException class with Exception as its parent class. An array of Po
inter is introduced in this class basically to store the error details that are
thrown within the application. This class has two constructors, the need for bot
h will be known when we implementation part. A record has been introduced which
can be changed by the implementor based on his requirements. Currently the recor
d stores the Unit Name, Method and Module name.
Before we get down to the actual code the let me explain the guidelines kept in
mind when designing the framework:
a) A complete traverse information of the exception.
b) A mechanism to display a meaningul information to the end user, but a detaile
d technical information to the developer.
c) Centralized Exception displaying and logging mechanism (Application.OnExcepti
on method).
{******************************************************************************}
{ }
{ Custom Exception class }
{ Author: Sri Ram Ambuga Nandakumar }
{ }
{ Disclaimer }
{ ---------- }
{ }
{ THE FILES ARE PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND WHETHER }
{ EXPRESSED OR IMPLIED. }
{ }
{ In no event shall the author be held liable for any damages whatsoever, }
{ including without limitation, damages for loss of business profits, }
{ business interruption, loss of business information, or any other loss }
{ arising from the use or inability to use the unit. }
{******************************************************************************}
unit UExceptionObj;
interface
uses
SysUtils;
type
PErrorDetails = ^TErrorDetails; //---------------------------
-------
TErrorDetails = record //
| Error Detail record.
sUnit: string; //
|-> Can be changed by the implementor
sModule: string; //
| To suit his requirement
sMethod: string; //
|
end; //---------------------------
-------
TCallStack = array of PErrorDetails;
// <- Array of Pointer
type
ECustomException = class(Exception)
private
FCallStack: TCallStack;
function GetStackLength: integer;
function GetErrorDetails(Index: integer): TErrorDetails;
protected
public
constructor Create(AMessage: string; AErrorDetails: TErrorDetails); overload
;
constructor Create(AMessage: string; AException: ECustomException); overload
;
destructor Destroy; override;
procedure AddToCallStack(AErrorDetails: TErrorDetails);
property StackLength: integer read GetStackLength;
property ErrorDetails[Index: integer]: TErrorDetails read GetErrorDetails; d
efault;
end;
implementation
{ ECustomException }
constructor ECustomException.Create(AMessage: string;
AErrorDetails: TErrorDetails);
begin
inherited Create(AMessage);
AddToCallStack(AErrorDetails);
end;
procedure ECustomException.AddToCallStack(AErrorDetails: TErrorDetails);
var
ptrErrDet: PErrorDetails;
begin
New(ptrErrDet);
ptrErrDet^ := AErrorDetails;
SetLength(FCallStack, High(FCallStack) + 2);
FCallStack[High(FCallStack)] := ptrErrDet;
end;
constructor ECustomException.Create(AMessage: string;
AException: ECustomException);
var
iCount: integer;
begin
inherited Create(AMessage);
for iCount := Low(AException.FCallStack) to High(AException.FCallStack) do
AddToCallStack(AException.FCallStack[iCount]^);
end;
destructor ECustomException.Destroy;
var
iCount: integer;
begin
inherited;
for iCount := Low(FCallStack) to High(FCallStack) do
Dispose(FCallStack[iCount]);
if Assigned(FCallStack) then
Finalize(FCallStack);
end;
function ECustomException.GetStackLength: integer;
begin
Result := High(FCallStack);
end;
function ECustomException.GetErrorDetails(Index: integer): TErrorDetails;
begin
if (Index > -1) and (Index < StackLength) then
Result := FCallStack[Index]^;
end;
end.
//******************************************************************************
**********************************
As we can see the Exception class takes care of storing the error information th
at are given to it. Now coming to the interface function which should be called
from all the procedures in the Application.
//******************************************************************************
**********************************
procedure GlobalExceptionHandler(AException: Exception; sUnit, sModule,
sProcedure: string);
var
recErrDet: TErrorDetails;
begin
recErrDet.sModule := sModule;
recErrDet.sProcedure := sProcedure;
recErrDet.sUnit := sUnit;
if AException is ECustomException then
begin
{ Here we can see if it is ECustomException then it adds the entry in the Ex
ception object and then raises the same error.
Note: since raise creates a new object the earlier exception's stack info
has to be passed on to the newly created one.
This is the purpose of one of the Constructor.
}
(AException as ECustomException).AddToCallStack(recErrDet);
raise ECustomException.Create(AException.Message, (AException as ECustomExce
ption));
end
else
{ If it is any other Error then create our exception class with the earlier
exception's message. This happens only at the source of the
error only that is for the first time. Additional code can be written here
to change the message of certain Exceptions like
if EAccessViolation then raise ECustomException.Create('An error occurre
d while accessing a resource', recErrDet); ;) }
raise ECustomException.Create(AException.Message, recErrDet);
end;
//******************************************************************************
**********************************
Additionally, this global exception handler can be fine tuned as per the require
ment of the application.
In the Application.OnException method just a loop will give all the information
about the exception.
Now all the methods in my application would look like below:
procedure TForm1.Button1Click(Sender: TObject);
begin
try
CallAProcedure
except
on E: Exception do
GlobalExceptionHandler(E, 'UnitName', Application.ExeName, 'Button1Click')
;
end;
end;

procedure CallAProcedure;
begin
try
CallRaiseAnException;
except
on E: Exception do
GlobalExceptionHandler(E, 'UnitName', Application.ExeName, 'CallAProcedure
');
end;
end;
procedure CallRaiseAnException;
begin
try
RaiseAnException;
except
on E: Exception do
GlobalExceptionHandler(E, 'UnitName', Application.ExeName,
'CallRaiseAnException');
end;
end;
procedure RaiseAnException;
begin
try
raise Exception.Create('This is the original error message');
except
on E: Exception do
GlobalExceptionHandler(E, 'UnitName', Application.ExeName,
'CallRaiseAnException');
end;
end;
Now in the above case when the exception object reaches the Application's
OnException method, the information of procedures that it will contain will be:
Button1Click
CallAProcedure
CallRaiseAnException
RaiseAnException.

Please let me know your opinions and views regarding the same
Sri Ram Ambuga Nandakumar
********************************************************************************
**
Hi Sriram
I have implemented the code from your article "Exception Handling in Delphi - Fr
amework to log the complete traverse information", but for some reason when I ru
n it (using your example) I don't get the Button1Click (in other words the initi
al method called to start the process) when I loop through the CallStack informa
tion. Here is th code that I am using:
function GetCallStackDetails(AException : Exception) : string;
var
recErrDet : TErrorDetails;
iCount : integer;
begin
Result := '';
for iCount := 0 to (AException as ECustomException).StackLength-1 do
begin
recErrDet := (AException as ECustomException).ErrorDetails[iCount];
Result := Result + recErrDet.sProcedure end;
end;
Respond
RE: Missing item on Call Stack
Derek Gibb (May 5 2006 2:58PM)
Hi Sriram
I have found what the problem was. You need to change the GetStackLength to the
following:
function ECustomException.GetStackLength: integer;
begin
Result := High(FCallStack)+1;
end;
Note the "+1". I am not sure why this is the case, but it appears to work now s
o I am not complaining.
Cheers
Derek
Respond
RE: RE: Missing item on Call Stack
Sriram Ambuga (May 5 2006 3:38PM)
Hello Derek,
Yes there is a problem in the code that is posted.
In the 'GetErrorDetails' method it should be (Index <= StackLength) instead of
Index < StackLength.
HTH.
Respond
RE: Missing item on Call Stack
Sriram Ambuga (May 5 2006 3:43PM)
Your solution works too.
Respond
RE: RE: Missing item on Call Stack
Derek Gibb (May 5 2006 6:25PM)
Thanks Sriram!
It is working perfectly now. I will try your solution when I get to work on Mon
day!
Cheers
Derek
Respond

S-ar putea să vă placă și