6

更新:它似乎特定于 D2007。它在 D2010 中工作,就像在旧版本中工作一样。

我想根据 Eception Handler 块中捕获的异常类型返回退出代码,例如:

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.

不幸的是,在 D2007 中,无论您将什么传递给 Halt(),从 Exception 块调用 Halt(n) 总是返回退出代码 1 。

显然是因为从异常处理程序中退出调用了 Finalize,它清除了挂起的(非 Abort)异常,调用了 SysUtils.ExceptHandler:

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

无论我想要什么退出代码,我都会得到它Halt(1)

所以问题是:
如何根据引发的异常简单地返回所需的退出代码?

4

5 回答 5

5

这行得通吗?

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); 

或这个?

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

无论如何:这是 D2007 中的错误,已在 D2010 中修复

于 2010-08-04T22:25:26.923 回答
2

实际上......它似乎按预期工作......

我用了你的代码...

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.

在 Delphi 5 中编译,然后在 XP 下的 DOS 框中运行它...

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

C:\>echo %errorlevel%
111

C:\>

请注意,DOS 错误级别限制在 0 到 65535 的范围内。回显 %errorlevel% 是查看错误级别的最快方法。

不要忘记读取错误级别会清除它。

于 2010-08-04T20:13:18.800 回答
2

如果您想立即中止程序而不进行任何清理并返回退出代码,请尝试ExitProcess。不过,请参阅文章了解有关使用 ExitProcess 的一些注意事项。

于 2010-08-04T20:16:55.810 回答
0

使用 halt(I) 会产生内存泄漏(您可以看到,如果您使用 ReportMemoryLeaksOnShutdown:=true; 启用 FastMM MemoryLeaks)

最好使用“干净”退出并在退出之前设置 ExitCode。

例如,在控制台应用程序的主要部分:

ExitCode:=I;
exit;
于 2016-03-04T18:44:50.403 回答
-1

如果内置的异常处理函数没有做你喜欢的,那么用你自己的替换它:

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

System.ExceptProc在程序启动时将其分配给全局变量:

ExceptProc := @ExitCodeExceptHandler;

我已经实现它以使用全局ExitCode变量。如果它仍然是默认值 0,那么该函数将恢复为以 1 退出的原始 Delphi 行为,但如果退出代码已经设置为其他值,那么它将以该值停止。首先要做的Halt是设置全局ExitCode变量,因此您的代码不需要进一步更改(尽管我会为Exitcode变量选择不同的名称)。您的调用Halt将设置全局ExitCode变量,然后继续关闭程序。异常处理程序会注意到已经设置并使用该值而不是 1ExitCode重新调用。Halt

于 2010-08-04T20:41:59.627 回答