2010-08-04 9 views
6

Update: Es scheint spezifisch für D2007 zu sein. Es funktioniert in D2010 wie es in der älteren Version funktioniert hat.Wie wird ein Fehlercode mit Halt (n) von einem Ausnahmeblock mit D2007 zurückgegeben?

Ich möchte einen Exit-Code zurück auf die Art der Ausnahme in dem Block eception Handler gefangen abhängig wie:

program test; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    Exitcode: Integer; 
begin 
    Writeln('Enter error code:'); 
    Readln(Exitcode); 
    try 
    raise EExternal.Create('sdsdkfjh'); 
    except 
    on E:EExternal do 
    begin 
     Writeln(E.Classname, ': ', E.Message); 
     Halt(Exitcode); 
    end; 
    end; 
end. 

Leider gibt es in D2007, Aufruf Halt (n) von einem Ausnahmeblock immer zurückkehrt ein Exit-Code 1, egal, was Sie an Halt() übergeben.

Offenbar, weil von einer Exception-Handler Verlassen ruft Finalize, die die anstehenden (nicht Abort) Ausnahmen löscht, ruft SysUtils.ExceptHandler:

procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); far; 
begin 
    ShowException(ExceptObject, ExceptAddr); 
    Halt(1); // <= @#$##@#$! 
end; 

Und egal, welchen Code Ausgang Ich wollte ich, dass Halt(1) bekommen!

Die Frage ist also:
Wie kann ich Dich einfach die Exit-Codes gewünscht je nachdem, welche Exception ausgelöst wurde?

+0

Basierend auf dem Kommentar unten von Mike, was wahr ist, ist es in der Tat die richtige Fehlercode zurückgibt. Ich vermute, dass es die Methode ist, die Sie verwenden, um den ErrorCode zu erhalten, der möglicherweise nicht wie erwartet funktioniert. – zz1433

+0

@ Aldo. Nein, es ist D2007. Die gleiche genaue Sache verhält sich anders mit D2007 und D2010, wo es zurück ist, wie ich von Mike erwartet und berichtet habe. –

+0

Bitte reichen Sie einen großen Bericht in QC (http://qc.embarcadero.com/); obwohl es wahrscheinlich kein D2007-Upgrade geben wird, ist es schön, dort sehen zu können, welche Bugs "bekannt" sind. –

Antwort

5

Funktioniert das?

NeedHalt := False; 
try 
    raise EExternal.Create('sdsdkfjh'); 
except 
    on E:EExternal do 
    begin 
    Writeln(E.Classname, ': ', E.Message); 
    NeedHalt := True; 
    end; 
end; 
if NeedHalt then 
    Halt(Exitcode); 

Oder das?

try 
    raise EExternal.Create('sdsdkfjh'); 
except 
    on E:EExternal do 
    begin 
    Writeln(E.Classname, ': ', E.Message); 
    AcquireExceptionObject; 
    Halt(Exitcode); 
    end; 
end; 

Wie dem auch sei: it's a bug in D2007, which was fixed in D2010.

+0

Danke! +1 für 'AcquireExceptionObject' ist der Trick für mich als Workaround in D2007. Das war in der Tat ein schöner Fehler ... –

2

Eigentlich ... es scheint, als beabsichtigt zu arbeiten ....

I Verwendung im Code ...

program test1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    Exitcode: Integer; 
begin 
    Writeln('Enter error code:'); 
    Readln(Exitcode); 
    try 
    raise EExternal.Create('sdsdkfjh'); 
    except 
    on E:EExternal do 
    begin 
     Writeln(E.Classname, ': ', E.Message); 
     Halt(Exitcode); 
    end; 
    end; 
end. 

Zusammengestellt in in Delphi 5, lief es dann in einer DOS-Box unter XP ...

C:\>test1 
Enter error code: 
111 
EExternal: sdsdkfjh 

C:\>echo %errorlevel% 
111 

C:\> 

Beachten Sie, dass DOS Fehlerebenen beschränkt auf den Bereich von 0 bis 65535. Hallend% Errorlevel% ist der schnellste Weg, um die Fehlerebene zu sehen.

Vergessen Sie nicht, dass das Lesen des Fehlerlevels es löscht.

+1

Funktioniert nicht mehr in D2007! Aber danke für die Bestätigung, dass es früher funktioniert hat! Ich war mir ziemlich sicher, dass ich es vorher schon gemacht hatte ... ;-) –

+1

Und es funktioniert auch in D2010. Derselbe genaue Code, die selbe genaue Art des Errorlevel Tests gibt mir, was ich in D2010 möchte, wie für dich mit D5, aber mit D2007 bekomme ich immer 1! –

2

Wenn Sie das Programm sofort ohne Bereinigung beenden und einen Beendigungscode zurückgeben möchten, versuchen Sie ExitProcess. Weitere Informationen zur Verwendung von ExitProcess finden Sie im Artikel.

+0

+1 für ExitProcess. Es ist ein bisschen zu hart für meinen jetzigen Fall, aber es lohnt sich, daran erinnert zu werden. –

-1

Wenn die integrierte Ausnahme-Handling-Funktion nicht tut, was Sie möchten, ersetzen Sie es dann mit Ihrem eigenen:

function ExitCodeExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); 
begin 
    ShowException(ExceptObject, ExceptAddr); 
    if ExitCode = 0 then 
    ExitCode := 1; 
    Halt(ExitCode); 
end; 

zuordnen, dass auf die globale Variable System.ExceptProc, wenn Ihr Programm beginnt:

ExceptProc := @ExitCodeExceptHandler; 

Ich habe es implementiert, um die globale ExitCode Variable zu verwenden. Wenn es immer noch den Standardwert 0 hat, kehrt die Funktion zum ursprünglichen Delphi-Verhalten von 1 zurück. Wenn der Exit-Code jedoch bereits auf etwas anderes gesetzt ist, wird stattdessen mit diesem Wert angehalten. Das erste, was Halt tut, ist die globale Variable ExitCode, so dass Ihr Code keine weiteren Änderungen benötigt (obwohl ich einen anderen Namen für die Variable Exitcode wählen würde). Ihr Aufruf an Halt setzt die globale Variable ExitCode und fährt dann mit dem Herunterfahren des Programms fort. Der Ausnahmebehandler wird feststellen, dass ExitCode bereits festgelegt ist, und rufen Sie Halt mit diesem Wert anstelle von 1 erneut auf.

+5

Leider funktioniert es nicht. Zuerst sollte es eine Prozedur sein, keine Funktion, aber wichtiger bei der Ankunft in 'DoneExceptions', der Code setzt 'ExceptProc: = nil' zurück und ruft dann direkt 'if (ExceptObject <> nil) und nicht (ExceptObject ist EAbort) auf ExceptHandler (ExceptObject, ExceptAddr); ' –

0

Mit halt (I) erzeugen Speicherlecks (Sie können sehen, dass, wenn Sie aktiviert das FastMM MemoryLeaks mit ReportMemoryLeaksOnShutdown: = true;)

Es ist viel besser, eine „Clean“ Exit zu verwenden und Exitcode vor dem Beenden .

In einem Hauptteil einer Konsole App zum Beispiel:

ExitCode:=I; 
exit;