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

发布于 2024-09-12 12:16:55 字数 915 浏览 4 评论 0原文

更新:似乎是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()。

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

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

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

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

Update: It seems to be specific to D2007. It works in D2010 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

八巷 2024-09-19 12:16:55

这行得通吗?

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 中修复

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.

留一抹残留的笑 2024-09-19 12:16:55

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

我使用了你的代码...

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% 是查看错误级别的最快方法。

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

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.

从来不烧饼 2024-09-19 12:16:55

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

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.

鲜血染红嫁衣 2024-09-19 12:16:55

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

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

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

ExitCode:=I;
exit;

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;
浅浅 2024-09-19 12:16:55

如果内置的异常处理函数不符合您的要求,请将其替换为您自己的:

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 变量,然后继续关闭程序。异常处理程序将注意到 ExitCode 已设置,并使用该值而不是 1 重新调用 Halt

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文