Delphi RSS Resources, Delphi Components, Delphi Sites, Articles, Dynamic XML Feeds, Tutorials, Sources
 
 
 
Google
 
Web delphirss.com
| Server-Scripts.com | Informations for JAVA | Informations for PHP | SEO Web Links | Borland Delphi
 

Exceptions

Respond an EConvertError before the application notifies the user
Exceptions
Trapping database exceptions
Circumvent the "Index not found" exception
Handling EDBEngineError Exceptions


Respond an EConvertError before the application notifies the user

Question

I'm using a DBEdit component for the user to enter data into a table's Date
field. If the user enters an invalid date - like 4/32/95 - Delphi will
raise an EConvertError. What I would like to do is respond to that error
before the application notifies the user of the bad data. I have tried the
Table's BeforePost and OnExit events - the DataSource's OnDataChange and
OnUpdateData - and the DBEdit's own OnExit.  All seem too late - the
exception has already been displayed to the user.

Any place to catch the DBEdit.Text after the user tries to leave the
component but before Delphi attempts the conversion?

Answer

A:
You could write your own exception handler to filter out the EConvertError.

Something like this:

Declare this procedure in your main form object:

    procedure MyException(Sender:TObject; E:Exception);

Then write it like this:

procedure TMyForm.MyException(Sender:TObject; E:Exception);
begin
  if (E.ClassType.ClassName='EConvertError') then
  begin
    {do something great to (or for) the user}
  end
  else Application.ShowException(E); {let Delphi take it from here}
end;

Finally set your application to use your new handler:

procedure TMyForm.FormCreate(Sender: TObject);
begin
     Application.OnException := MyException;
end;


Exceptions

Question

I wanted to write some fairly simple code...

procedure part_of_starting_up(n:string....)
var f: typed file;
begin
 try
  assign/reset(f,n);
  while not eof(f) do
     read_and_process_each_record(f);
  close(f);
 except
  on exxxxx do messagedlg('couldn't find/open file');
  on eyyyyy do
   begin
    messagedlg('error reading file');
    close(f);
   end
(etc)

where exxxx = the exception created when reset failed,
and  eyyyy = any exception occuring in my (dumb) file reading code.
The key point, of course, is making sure that the file is closed if
it was opened. (note: "fileExists" may not mean "file can be opened")

I RTFM'd and used the browser, but am still confused as to what e____'s
relate to this kind of file management. Is what I'm trying to do possible?
Or should I do

  try
   assign/reset/readthefile
  except blahblahblah
  try
   close;
  except (*nothing*)

Answer

Try this scheme. It worked for me.


procedure part_of_starting_up(n:string....)
var f: typed file;
begin 
     try
          try
               assign/reset(f,n);
               while not eof(f) do
               read_and_process_each_record(f);
          finally
               {$i-}     { No need to complain if close fails. }
               close(f);
               {$i+}
          end;
     except
          on E:EInOutError do 
               case e.ErrorCode of
               nn1: messagedlg('couldn't find/open file');
               nn2: messagedlt('error reading file');
               end;
     end
(etc)

Keep in mind that for the type of functions you are using you will
get the same exception, called EInOutError. You have to use the errorcode 
field to know what message to show. 

A:
You cannot combine except & finally in a try clause, unfortunately or wisely.

Trapping database exceptions

Question

Can anyone tell me how I can abort a change-of-focus from within an
OnExit event?

procedure DBEdit1OnExit(Sender : TObject);
begin
  try
    Tabl.Post;
  except
     On EDatabaseError do ShowMessage('Cannot Post');
  end;
end;

Also, can anyone explain how I can "isolate" specific EDatabaseErrors?

Finally, has anyone else noticed that EDatabase exceptions ALWAYS get
handled by the default handler (which stops the app) when running
under the Delphi IDE?  The problem (feature?) goes away when the
application is not running within Delphi.

Answer

A:
Try
  Tabl.Post;
Except
  Begin
    On EDatabaseError do ShowMessage('Cannot Post');
    (Sender AS TDBEdit).SetFocus;
  End;	{Begin}
End,	{Try}

I am parsing the Error and reraising the exception if I am not going to deal
with it. If you use

On E : EDatabaseError do...

you can get the value of E.Error. This is OTTOMH as I am not lookin at Delphi,
its probably something like E.Message (it is in the help).

A:
On EDatabaseError do begin
       ShowMessage('Cannot Post');
       Edit1.setFocus;
    end;

Circumvent the "Index not found" exception

Question

How do I open a dBASE table without the required MDX file?
I keep getting an "Index not found..." exception.

Answer

{

A: When you create a dBASE table with a production index (MDX), a 
   special byte is set in the header of the DBF file.  When you
   subsequently attempt to re-open the table, the dBASE driver
   will read that special byte, and if it is set, it will also
   attempt to open the MDX file.  When the MDX file cannot be
   opened, an exception is raised.

   To work around this problem, you need to reset the byte (byte
   28 decimal) in the DBF file that causes the MDX dependency
   to zero.

   The following unit is a simple example of how to handle the 
   exeption on the table open, reset the byte in the DBF file,
   and re-open the table.
}
unit Fixit;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, 
  Controls, Forms, Dialogs, StdCtrls, DB, DBTables, Grids, DBGrids;

type
  TForm1 = class(TForm)
    Table1: TTable;;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var

  Form1: TForm1;

implementation

{$R *.DFM}

const
  TheTableDir = 'c:\temp\';
  TheTableName = 'animals.dbf';

procedure RemoveMDXByte(dbFile: String);
{ This procedure accepts a DBF file as a parameter.  It will patch}
{ the DBF header, so that it no longer requires the MDX file }
const
  Value: Byte = 0;
var
  F: File of byte;
begin
  AssignFile(F, dbFile);
  Reset(F);
  Seek(F, 28);
  Write(F, Value);
  CloseFile(F);
end;

procedure TForm1.Button1Click(Sender: TObject);
{ This procedure is called in response to a button click.  It    }
{ attempts to open a table, and, if it can't find the .MDX file, }
{ it patches the DBF file and re-execute the procedure to        }
{ re-open the table without the MDX  }
begin
  try
    { set the directory for the table }
    Table1.DatabaseName := ThheTableDir;
    { set the table name }
    Table1.TableName := TheTableName;
    { attempt to open the table }
    Table1.Open;
  except
    on E:EDBEngineError do
      { The following message indicates the MDX wasn't found: }
      if Pos('Index does not exist. File', E.Message)>0 then begin
        { Tell user what's going on. }
        MessageDlg('MDX file not found.  Attempting to open 
                    without index.', mtWarning, [mbOk], 0);
        { remove the MDX byte from the table header }
        RemoveMDXByte(TheTableDir + TheTableName);
        { Send the button a message to make it think it was }
        { pressed again.  Doing so will cause this procedure to }
        { execute again, and the table will be opened without }
        { the MDX }
        PostMessage(Button1.Handle, cn_Command, bn_Clicked, 0);
      end;
  end;
end;

end.


Handling EDBEngineError Exceptions

Question

How to handle with EDBEngine exceptions?

Answer

Information that describes the conditions of a database engine error can
be obtained for use by an application through the use of an EDBEngineError
exception. EDBEngineError exceptions are handled in an application through
the use of a try..except construct. When an EDBEngineError exception
occurs, a EDBEngineError object would be created and various fields in that
EDBEngineError object would be used to programmatically determine what
went wrong and thus what needs to be done to correct the situation. Also,
more than one error message may be generated for a given exception. This
requires iterating through the multiple error messages to get needed info-
rmation.

The fields that are most pertinent to this context are:

   ErrorCount: type Integer; indicates the number of errors that are in
     the Errors property; counting begins at zero.

   Errors: type TDBError; a set of record-like structures that contain
     information about each specific error generated; each reecord is
     accessed via an index number of type Integer.

   Errors.ErrorCode: type DBIResult; indicating the BDE error code for the
     error in the current Errors record.

   Errors.Category: type Byte; category of the error referenced by the
     ErrorCode field.

   Errors.SubCode: type Byte; subcode for the value of ErrorCode.

   Errors.NativeError: type LongInt; remote error code returned from the
     server; if zero, the error is not a server error; SQL statement
     return codes appear in this field.

   Errors.Message: type TMessageStr; if the error is a server error, the
     server message for the error in the current Errors record; if not a
     server error, a BDE error message.

In a try..except construct, the EDBEngineError object is created directly
in the except section of the construct. Once created, fields may be
accessed normally, or the object may be passed to another procedure for
inspection of the errors. Passing the EDBEngineError objject to a special-
ized procedure is preferred for an application to make the process more
modular, reducing the amount of repeated code for parsing the object for
error information. Alternately, a custom component could be created to
serve this purpose, providing a set of functionality that is easily trans-
ported across applications. The example below only demonstrates creating
the DBEngineError object, passing it to a procedure, and parsing the
object to extract error information.

In a try..except construct, the DBEngineError can be created with syntax
such as that below:

  procedure TForm1.Button1Click(Sender: TObject);
  var
    i: Integer;
  begin
    if Edit1.Text > ' ' then begin
      Table1.FieldByName('Number').AsInteger := StrToInt(Edit1.Text);
      try
        Table1.Post;
      except on E: EDBEngineError do
        ShowError(E);
      end;
    end;
  end;

In this procedure, an attempt is made to change the value of a field in a
table and theen call the Post method of the corresponding TTable component.
Only the attempt to post the change is being trapped in the try..except
construct. If an EDBEngineError occurs, the except section of the con-
struct is executed, which creates the EDBEngineError object (E) and then
passes it to the procedure ShowError. Note that only an EDBEngineError
exception is being accounted for in this construct. In a real-world sit-
uation, this would likely be accompanied by checking for other types of
exceptions.

The procedure ShowError takes the EDBEngineError, passed as a parameter,
and queries the object for contained errors. In this example, information
about the errors are displayed in a TMemo component. Alternately, the
extracted values may never be displayed, but instead used as the basis for
logic branching so the application can react to the errors. The first step
in doing this is to establish the number of errors that actually occurred.
This is the purpose of the ErrorCounnt property. This property supplies a
value of type Integer that may be used to build a for loop to iterate
through the errors contained in the object. Once the number of errors
actually contained in the object is known, a loop can be used to visit
each existing error (each represented by an Errors property record) and
extract information about each error to be inserted into the TMemo comp-
onent.

  procedure TForm1.ShowError(AExc: EDBEngineError);
  var
    i: Integer;
  begin
    Memo1.Lines.Clear;
    Memo1.Lines.Add('Number of errors: ' + IntToStr(AExc.ErrorCount));
    Memo1.Lines.Add('');
    {Iterate through the Errors records}
    for i := 0 to AExc.ErrorCount - 1 do begin
      Memo1.Lines.Add('Message: ' + AExc.Errors[i].Message);
      Memo1.Lines.Add('   Category: ' + 
        IntToStr(AExc.Errors[i].Category));
      Memo1.Lines.Add('   Error Code: ' + 
        IntToStr(AExc.Errors[i].ErrorCode));
      Memo1.Lines.Add('   SubCode: ' + 
        IntTooStr(AExc.Errors[i].SubCode));
      Memo1.Lines.Add('   Native Error: ' + 
        IntToStr(AExc.Errors[i].NativeError));
      Memo1.Lines.Add('');
    end;
  end;










© DelphiRSS.com. All Rights Reserved.