[ Milos D @ 28.10.2005. 12:08 ] @
Šta koristite u vašim programima kako bi "kulturno" obradili exception-e kod krajnjeg korisnika? Znači poželjno da napravi neki report u kojem je call stack i linija koda gde je bila greška umesto default beskorisnih poruka. MadExcept deluje lepo i profesionalno, ali nije baš jeftin, 100$ a i kupovinom se ne dobijaju buduće verzije. Neki drugi alati koje sam pogledao deluju pomalo neozbiljno i "krhko"...
[ _v!rus_ @ 28.10.2005. 20:02 ] @
Mislim da ne mozes tacno dobiti podatak u kojoj liniji koda je doslo do greske, osim ako ne koristis neki debugger i uradis build sa debug informations.

Ali mozes koristiti Assert tako sto ces postaviti flag [{$ASSERTIONS ON}] u src projekta i onda kada god uradis npr.
Code:

try
  ...
except
  Assert(False, 'npr. <record update failed!>')
end;

dobices exception #227 ako se pozove Assert.

Moze se koristiti i npr.
Code:

Assert(CopyFile(...), 'CopyFile failed');
//Kopiranje ce se izvrsiti ako je sve ok
//ako nije, tj CopyFile vrati false, izvrsice se assert
Assert(Now < TimeOut, 'Timeout error')
///itd.


Exception #227 ces overridovati tako sto ces dodeliti ugradjeni procedure pointer AssertErrorProc na neku svoju proceduru koja je u obliku
Code:

procedure MyEAssertProc(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);


Znaci. napises nesto ovako u glavnom fajlu projekta (dpr).
Code:

program ...

uses
  SysUtils,
...

{$ASSERTIONS ON}

procedure MyEAssertHandler(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
const
  DebugFileName = 'C:\Debug.txt';
var
  DebugFile: TextFile;
  ErrorAddress: String;
begin
  AssignFile(DebugFile, DebugFileName);
  if FileExists(DebugFileName) then
    Append(DebugFile)
  else
    ReWrite(DebugFile);
  ErrorAddress := IntToHex(Integer(ErrorAddr), 0);
  WriteLn(DebugFile, '***' + FormatDateTime('dd.MM.yyyy hh:nn', Now) + ' Error at adress ' + ErrorAddress + ' near line #' + IntToStr(LineNumber) + ' in ' + ExtractFileName(FileName) + ': ' + Message);
  CloseFile(DebugFile);
end;

begin
  Application.Initialize;
  AssertErrorProc := @MyEAssertHandler;
...
end.


Samo da znas, Line# je broj linije gde je pozvan Assert a ne gde je zaista doslo do greske, ali i to je najcesce sasvim dovoljno da resis problem.

Jos jedna dobra strana ovog metoda je i to sto mozes da logujes svoj tip gresaka ili upozorenja, npr. Assert(False, 'User canceled, exiting silently').
[ morlic @ 28.10.2005. 20:21 ] @
Naravno da moze da se dobije broj linije i to tacan. Imas u okviru JCL paketa podrsku za to. Ja sam za svoje potrebe napravio mali unit koji mi belezi sve sto je moguce u datoj situaciji. Tu je podatak u kom modulu je doslo do greske, u kojoj linij koda, zatim stack, a moguce je videti i kako je na kraju exception zavrsio. Krajnje korisno i hvata izuzetke bez obzira sto ih mozda u kodu hvatas sa except...end blokom i "ubijas".

Znaci pogledaj:

JclDebug, JclHookExcep unite i mislim da ima i neki primer za koriscenje koji dolazi u z JCL paket.
[ Trodmi @ 30.10.2005. 00:36 ] @
Bolje spreciti nego leciti
[ Milos D @ 30.10.2005. 14:51 ] @
OK hvala pogledaću JCL.

Naravno, bolje sprečiti nego lečiti. Samo... kada program postane dovoljno velik, koriste se hiljade linija 3rd party koda, a korisnik ima neki egzotičan softver/hardver... tada dobro dodje da korisnik pošalje neki error report sadržajniji od screenshot-a na kome piše access violation - read of address FFFFFFFF...

[Ovu poruku je menjao Milos D dana 30.10.2005. u 16:29 GMT+1]
[ Trodmi @ 04.11.2005. 12:24 ] @
100 % si u pravu. Ja sam koristio Jedi za neke panele u svojoj aplikaciji i nesto slicno se desilo. To je cena koju sam platio zbog malo sarenila na formi.