How to return an error code with Halt(n) from an Exception block with D2007?
Update: It seems to be specific to D2007. It works in D开发者_如何学运维2010 like it worked in older version.
I would like to return an exit code depending on the type of Exception caught in the Eception Handler block like:
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.
Unfortunately in D2007, calling Halt(n) from an Exception block always returns an Exit code 1, no matter what you pass to Halt().
Apparently because exiting from an Exception handler calls Finalize, which clears the pending (non Abort) Exceptions, calling SysUtils.ExceptHandler:
procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); far;
begin
ShowException(ExceptObject, ExceptAddr);
Halt(1); // <= @#$##@#$!
end;
And no matter what exit code I wanted I get that Halt(1)
!
So the question is:
How can I simply return the desired Exit code depending on which Exception was raised?Will this work?
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);
Or this?
try
raise EExternal.Create('sdsdkfjh');
except
on E:EExternal do
begin
Writeln(E.Classname, ': ', E.Message);
AcquireExceptionObject;
Halt(Exitcode);
end;
end;
Anyway: it's a bug in D2007, which was fixed in D2010.
Actually... it seems to work as intended....
I used your 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.
Compiled in in Delphi 5, then ran it in a DOS box under XP...
C:\>test1
Enter error code:
111
EExternal: sdsdkfjh
C:\>echo %errorlevel%
111
C:\>
Note that DOS Error Levels are restricted to the range of 0 to 65535. Echoing %errorlevel% is the quickest way to see the error level.
Don't forget that reading the errorlevel clears it.
If you want to immediately abort the program without any cleanup, and return an exit code, try ExitProcess. See the article for a few caveats on using ExitProcess, though.
Using halt(I) generates memory leaks (you can see that if you enabled the FastMM MemoryLeaks with ReportMemoryLeaksOnShutdown:=true;)
It's much better to use a "Clean" Exit and set ExitCode prior to exiting.
In a main section of a console app for instance:
ExitCode:=I;
exit;
If the built-in exception-handling function doesn't do what you like, then replace it with your own:
function ExitCodeExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer);
begin
ShowException(ExceptObject, ExceptAddr);
if ExitCode = 0 then
ExitCode := 1;
Halt(ExitCode);
end;
Assign that to the global System.ExceptProc
variable when your program starts:
ExceptProc := @ExitCodeExceptHandler;
I've implemented it to use the global ExitCode
variable. If it's still at its default value of 0, then the function reverts to the original Delphi behavior of exiting with 1, but if the exit code has already been set to something else, then this will halt with that value instead. The first thing Halt
does is set the global ExitCode
variable, so your code should need no further changes (although I'd choose a different name for the Exitcode
variable). Your call to Halt
will set the global ExitCode
variable and then proceed to shut down the program. The exception handler will notice that ExitCode
is already set and re-call Halt
with that value instead of 1.
精彩评论