Solved

Global Exception Handler Solution

Posted on 2010-11-09
14
604 Views
Last Modified: 2012-06-27

I need a global exception handler solution for my application.

As an example: lets say i only have two forms (main form -frmMain, and data module form - frmDataMod


I need to be able to kick out of the entire application when an acception has occurred. Whether im in the main form, or in the datamod form.

Currently, when the datamod is created in the main source, if an exception happens (Example: Database not found), it throws the exception message, and doe not terminate the entire app, it loads the main form

I dont understand why?  Please help?

thanks


Currently, when an exception happens in the datamodule, it is handled, i get the raised exception,


{PROJECT SOURCE}





begin

 GlobalExcept := nil;

 GlobalExceptAddr := nil;



  //first check for license file

 gLicenseFound:=  FileExists(ChangeFileExt(Application.ExeName, '.lcs'));

 SL:= TStringList.Create;

 if gLicenseFound then

 begin

 //open license file and read in data



  try

   SL.LoadFromFile(ChangeFileExt(Application.ExeName, '.lcs'));

   Cipher:= TDCP_rc4.Create(nil);

   Cipher.InitStr('genie',TDCP_sha1);

   SL.CommaText:= Cipher.DecryptString(SL.CommaText);

   Cipher.Burn;

   Cipher.Free;

  except

  end; //try



  if SL.Count = 5 then

  begin

   gRegLast:= SL[0];

   gRegFirst:= SL[1];

   gRegEMail:=  SL[2];

   gRegDate:= SL[3];

   gRegDays:= SL[4];

  end //if SL.Count = 5 then

  else

  begin

   raise ECustomException.Create('Invalid License!');

   Application.Terminate;

  end; //else

 end; //if LicenseFound then

 //free list

 SL.Free;



 AppMsg := RegisterWindowMessage('Genie_Win_Message');

 Mutex := CreateMutex(nil, True, 'Genie_Mutex_Name');

 if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then

 begin

  SendMessage(HWND_BROADCAST, AppMsg, 0, 0);

  raise ECustomException.Create(('An Instance is already running!');

 end //if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then

 else

 begin

  

  try

   Application.Initialize;

   if gDBPath = '' then

   begin

    //prompt user for the location of database

      frmDBSettings:= TfrmDBSettings.Create(Application);

      if frmDBSettings.ShowModal = mrOK then

      begin

       WriteRegSettings;

      end; //if frmDBSettings.ShowModal = mrOK then

     end;

     frmDBSettings.free;

     frmSplash:= TfrmSplash.Create(Application);

     //fill splash screen form controls here

     frmSplash.Show;

     frmSplash.Update;

     Application.ProcessMessages;

     if gDBPath <> '' then

     begin

      Application.CreateForm(TfrmDataMod, frmDataMod);

      Application.CreateForm(TfrmMain, frmMain);

      Application.ProcessMessages;

      Sleep(3000);

      frmSplash.Close;

      frmSplash.Free;

      Application.Run;

     end; //if DBPath <> '' then

     finally

     if Assigned( GlobalExcept ) then

     begin

      raise GlobalExcept at GlobalExceptAddr;

     end; //if Assigned( GlobalExcept ) then

    end; //try

   end; //else

   if Mutex <> 0 then

    CloseHandle(Mutex);

end.



{COMMON UNIT SHARED WITH MAIN SOURCE AND TWO FORMS}



type

  

  ECustomException = Class(Exception);



var

 GlobalExcept: Exception;

 GlobalExceptAddr: Pointer;





{DATA MODULE FORM CREATION}



procedure TfrmDataMod.DataModuleCreate(Sender: TObject);

begin

 gAppPath:= ExtractFilePath(Application.ExeName);

 if gDBPath = '' then gDBPath:= ChangeFileExt(Application.ExeName, '.dat');

 if FileExists(gDBPath) then

 begin

  dbMain.ConnectionString:=  'Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Database Password=TEST_DBA;' +

                             'Data Source=' + gDBPath + ';' +

                             'Persist Security Info=False';

 try

  dbMain.Connected:= True;

  if dbMain.Connected then

  begin

   //

  end; //if

 except

  raise ECustomException.Create('Error Opening Database!');

  Application.TErminate;

 end; //try

 end

 else

 begin

  raise ECustomException.Create(Database not found!');

  Application.Terminate;

 end;

end;

Open in new window

0
Comment
Question by:Looking_4_Answers
  • 5
  • 3
  • 3
  • +1
14 Comments
 

Author Comment

by:Looking_4_Answers
ID: 34093604
sorry , i forgot the exception handler

procedure TrmMain.ApplicationException(Sender: TObject; E: Exception);
begin
  if E is EAccessViolation then
  begin
    // Keep the exception object from being destroyed!
    AcquireExceptionObject;
    GlobalExcept := e;
    GlobalExceptAddr := ExceptAddr;
    Application.Terminate;
  end;
end;
0
 

Author Comment

by:Looking_4_Answers
ID: 34093817
i also tried moving the creation of the datamod up above the creation of the splash screen

 begin
  Application.Initialize;
  Application.CreateForm(TfrmDataMod, frmDataMod);
  frmSplash:= TfrmSplash.Create(Application);
  //fill splash screen form controls here
  frmSplash.Show;
  frmSplash.Update;
  Application.CreateForm(TfrmMain, frmMain);
  frmSplash.Close;
  frmSplash.Free;
  Application.Run;
 end;//else

 finally
 if Assigned( GlobalExcept ) then
 begin
  raise GlobalExcept at GlobalExceptAddr;
 end; //if Assigned( GlobalExcept ) then
 end; //try


still, if an exception occurs in the datamod form, the main form still loads after the exception message!
0
 
LVL 14

Expert Comment

by:systan
ID: 34093946
>>still, if an exception occurs in the datamod form, the main form still loads after the exception message!
>>I need to be able to kick out of the entire application when an acception has occurred. Whether im in the main form, or in the datamod form.

Ahm, try
//halt;
if Assigned( GlobalExcept ) then halt;


Sorry If I understood it wrong
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34094218
You have an exception handler in the main form while your error occurs even before the mainform is created

Some of your code needs to be moved to the main form especially the cases where you are raising the exceptions
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34094226
when you raise an exception, the code jumps out immediately after to the next exception handler.
So :
try
...
 except
  raise ECustomException.Create('Error Opening Database!');
   Application.TErminate; // THAT CODE NEVER EXECUTES
 end;

do it in the other order
try
 ...
 except
   Application.Terminate;
   raise ECustomException.Create('Error Opening Database!');
end;
 
0
 

Author Comment

by:Looking_4_Answers
ID: 34094433
@ epasquier


so why do i even need the Application.Terminate anyways????

why doesn't the raise kick it to the  ApplicationException  which has the terminate

procedure TrmMain.ApplicationException(Sender: TObject; E: Exception);
begin
  if E is EAccessViolation then
  begin
    // Keep the exception object from being destroyed!
    AcquireExceptionObject;
    GlobalExcept := e;
    GlobalExceptAddr := ExceptAddr;
    Application.Terminate;
  end;
end;

i have one of these in each of the two forms

@ewangoya:

Please tell me what code needs to go where. I have the same code (ApplicationException) as i described above, in each form, and both forms use the commonunit



0
 

Author Comment

by:Looking_4_Answers
ID: 34094519
@ epasquier

after testing your suggestion to reverse, the result are that the application is terminated and there is no exception message raised.

In some cases, depending on the exception, I get the MS Windows window "GSM.exe has encountered a problem and needs to close.  We are sorry for the inconvenience." with the send or dont send buttons to report it to microsoft


0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:Looking_4_Answers
ID: 34094528
@systan:

where should i try this?

if Assigned( GlobalExcept ) then halt;
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34094588
>> so why do i even need the Application.Terminate anyways????
well, to tell the application to terminate when it will be in the Application.Run method.
That has no other use, Terminate only signals Application to quit the main message loop when the WM_QUIT message will be treated (by setting FTerminate := True).

FYI , Run loop is mainly this
repeat
  HandleMessage
until Terminated;  // = FTerminate

To immediately stop the application, use Halt;
example :
instead of
   raise ECustomException.Create('Invalid License!');
   Application.Terminate;
put
   ShowMessage('Invalid License!');
   Halt;


>> why doesn't the raise kick it to the  ApplicationException  which has the terminate
because when the exception occurs, you haven't yet create the form. I don't know where you associated that event to Application.OnException
It is not enough to declare an exception handler, you also must set it in the application's event property

you also don't need one per form. I recommend you declare ONE handler in the first module you create, and set Application.OnException right in the creation of this module (TfrmDataMod)
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34094667
Move datamodule creation to after MainForm Creation

In your MainForm.OnShow, check for the license


procedure TMainForm.FormShow(Sender: TObject);
var
  SL: TStringList;
begin
 //first check for license file
 gLicenseFound:=  FileExists(ChangeFileExt(Application.ExeName, '.lcs'));
 SL:= TStringList.Create;
 try
   if gLicenseFound then
   begin
   //open license file and read in data

    try
     SL.LoadFromFile(ChangeFileExt(Application.ExeName, '.lcs'));
     Cipher:= TDCP_rc4.Create(nil);
     try
       Cipher.InitStr('genie',TDCP_sha1);
       SL.CommaText:= Cipher.DecryptString(SL.CommaText);
       Cipher.Burn;
     finally
       Cipher.Free;
    except
    end; //try

    if SL.Count = 5 then
    begin
      gRegLast:= SL[0];
      gRegFirst:= SL[1];
      gRegEMail:=  SL[2];
      gRegDate:= SL[3];
      gRegDays:= SL[4];
    end //if SL.Count = 5 then
    else
    begin
     //no need for exception
     MessageDlg('Invalid License!', mtError, [mbOk], 0);
     PostMessage(Handle, WM_CLOSE, 0, 0);
     Exit
    end; //else
   end; //if LicenseFound then
  finally
     SL.Free;
  end;
end;

in your datamodule create


procedure TfrmDataMod.DataModuleCreate(Sender: TObject);
  procedure PerformExit(const AMessage: string);
  begin
    MessageDlg(AMessage, mtError, [mbOK], 0);
    PostMessage(Application.MainForm.Handle, WM_CLOSE, 0, 0);
  end;
begin
  gAppPath:= ExtractFilePath(Application.ExeName);
  if gDBPath = '' then
    gDBPath:= ChangeFileExt(Application.ExeName, '.dat');
  if FileExists(gDBPath) then
  begin
    dbMain.ConnectionString:=  'Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Database Password=TEST_DBA;' +
                             'Data Source=' + gDBPath + ';' +
                             'Persist Security Info=False';
  try
    dbMain.Connected:= True;
    if dbMain.Connected then
    begin
     //
    end; //if
  except
    //no need for exception
    PerformExit('Error Opening Database!');
    Exit;
  end; //try
  end
  else
  begin
    PerformExit('Database not found!');
    Exit;
  end;
end;
0
 
LVL 25

Accepted Solution

by:
epasquier earned 500 total points
ID: 34094769
> Move datamodule creation to after MainForm Creation
that is generally a bad idea. Datamodules are often regrouping resources needed for all the application. It is best created before all forms

for better clarity in your code, I would recommend putting everything you check at application start in the datamodule creation, just after setting the Application.onException handler, just to keep the main code in your project source minimal, AND standard (like what Delphi generates when you add autocreated forms in your project)

use of Halt is the quickest way to get away on application initialization. Just not recommended when you have loaded a lot of data /system resources that could use some cleaner exit (general advice : avoid if you have created forms)
0
 
LVL 14

Expert Comment

by:systan
ID: 34094884
finally
 if Assigned( GlobalExcept ) then
 begin
 halt;
 // raise GlobalExcept at GlobalExceptAddr;
 end; //if Assigned( GlobalExcept ) then
 end; //try
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34094979
@epasquire
Correct if the mainform uses resources from the datamodule then the mainform can not be created before the datamodule
0
 
LVL 14

Expert Comment

by:systan
ID: 34098110
Why use datamodule?, While you can asssign/create nil.

adoquery: tadoquery;
adocon: tadoconnection;
adotran: tadotransaction;
..
..
adoquery := tadoquery.create(nil);
adocon := tadocon.create(nil);
...
...
adoquery.connection := adocon;
adotran.open;
adoquery.transaction := adotran;
adoquery.sql.text := ;select * from table';
adoquery.open
...
..
just like that, incase your interested, i'll show you more.
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now