如何使用D2007从异常块中使用Halt(n)返回错误代码?

时间:2010-08-04 19:56:25

标签: delphi exception delphi-2007 exit-code halt

更新:它似乎特定于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(n)始终返回退出代码1 ,无论您传递给Halt()。

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

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

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

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

5 个答案:

答案 0 :(得分: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;

无论如何:it's a bug in D2007, which was fixed in D2010

答案 1 :(得分: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%是查看错误级别的最快方法。

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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

使用&#34; Clean&#34;会好得多。退出并在退出前设置ExitCode。

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

ExitCode:=I;
exit;

答案 4 :(得分:-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,那么该函数将恢复为原始Delphi行为,退出时为1,但如果退出代码已经设置为其他内容,那么这将停止使用该值。 Halt做的第一件事是设置全局ExitCode变量,因此您的代码不需要进一步更改(尽管我为Exitcode变量选择了不同的名称)。您对Halt的调用将设置全局ExitCode变量,然后继续关闭该程序。异常处理程序会注意到ExitCode已设置,并使用该值而不是1重新调用Halt