当未使用 Environment.Exit() 时,.net 程序可以具都有哪些退出代码?

Posted

技术标签:

【中文标题】当未使用 Environment.Exit() 时,.net 程序可以具都有哪些退出代码?【英文标题】:Which exit codes can a .net program have, when Environment.Exit() is not used?当未使用 Environment.Exit() 时,.net 程序可以具有哪些退出代码? 【发布时间】:2015-12-08 18:19:07 【问题描述】:

如果 .net 程序在终止之前未能明确设置退出代码(通过调用 Environment.Exit() / Appliation.Current.Shutdown() / ...),那么该进程的退出代码是什么?

正常终止是否总是导致退出代码为零,其他可能的情况是什么?

根据this answer Hans Passant 的相关问题Getting ExitCode From Exception Handler:“如果程序因异常而死,那么它的退出代码通常与底层异常错误相同代码”。

因此,未捕获的异常可以改变退出代码。是否总是如此,底层异常错误代码是否总是保证不同于零,并且在特定范围内?

在其他情况下,.net 框架或 Windows 是否可以自动设置另一个退出代码,例如一些非异常相关的崩溃(这可能吗?),或强制任务终止?

换句话说,我可以通过退出代码确定程序是否以任何异常方式终止吗? 或者如果在某些异常情况下也可能发生退出代码为零,我是否可以在程序的所有正常终止路径中包含Environment.Exit(somevalue),并确保在崩溃的情况下永远不会出现此退出代码?


动机: 由于not all exeptions are catchable 没有严重的变通办法,并且由于除了未捕获的异常之外可能还有其他原因导致程序突然终止,因此确保所有代码路径都调用 Environment.Exit() 是不可能的。这就是为什么我有兴趣确定退出代码是否可以用来可靠地判断程序是否正常退出。

【问题讨论】:

我添加了我的问题和建议的副本之间的差异。虽然第二个答案也对我的部分问题有所帮助,但它并没有完全回答它,而且问题本身完全不同。 切线建议:启用 Windows 错误报告,并启用创建小型转储的选项。这样,您不仅有一个退出代码,还有您可以通过调试器传递的异常记录和部分堆栈。 (就像使用 SOS 调试器的 WinDBG。)即使没有小型转储,WER 也会捕获有关错误消息本身的一些信息。对于内部应用程序,您甚至可以设置服务器以自动提交崩溃报告。 TechNet 上的这个page 有一个很好的概述。 退出代码非常没用恕我直言。更多信息:***.com/questions/4344923/… 【参考方案1】:

那么它的退出代码通常与底层异常错误代码相同

6 个月后,您应该对通常适用。可能工作得很好,你只是不能在这里获得保修。导致进程终止的不仅仅是未处理的异常,而且您永远无法确定当进程因异常而死时运行的代码总是相同的。

想要参与其中的东西太多了,而且质量并不总是最好的。最重要的当然是反恶意软件,那里有很多 cr*pware,你永远不会知道你遇到了什么。最近的 Avast 灾难让我们有充分的理由对此感到担忧。几乎没有结束,取代 WER 的实用程序已经足够普遍了。

对于一个认为 TerminateProcess() 是解决文件锁定问题的好方法的笨蛋,你完全无能为力。或者有人绊倒电源线并拔下机器。

关注一下为什么你想知道退出代码。接下来应该做一些事情,使用程序的结果继续执行。验证结果。

【讨论】:

【参考方案2】:

您正在执行的流程是您自己的流程吗?也就是说,你能在可预测的情况下控制它的退出代码吗? 如果是这样,您可以捕获任何抛出的异常,然后返回您自己的可预测的非零异常代码(特定值或您自己的范围)。我会使用负数,因为系统错误代码是正数。 这样你就有了三种可能性:

    零 - 成功 否定 - 进程引发了您能够捕获的异常 肯定 - 进程引发了您无法捕获的异常。那是不正常的。

除此之外的任何事情似乎都无法预测。如果某些事情超出正常范围以至于进程甚至无法返回非零退出代码,那么等待该退出代码的进程也可能失败。检查非零退出代码是您可以合理地考虑由于任何不可预见的原因而导致失败的可能性。

我不知道#3 是否可能,但如果你试图解释未知数,那么这可能是你能做的最多的事情了。

这是一个例子:

internal class Program

    private static void Main(string[] args)
    
        var exitCode = 0;
        try
        
            //do something
        
        catch (SystemException systemEx)
        
            //log
            exitCode = -systemEx.HResult;
        
        catch (Exception ex)
        
            //log
            Environment.ExitCode = int.MinValue;

        
        Environment.ExitCode = exitCode;
    

这是你可以做的。但我不会使用退出代码来描述错误。我会为此使用日志记录。我会使用退出代码来告诉调用应用程序要做什么。零或非零可能就足够了。我编写了更复杂的返回代码来指示失败是与 IO 相关还是与 SQL 相关,最后我从未使用过任何一个。如果失败,我会查看我的日志以获取错误消息。

【讨论】:

相当确定您的意思是 exitCode = int.MinValue 在基本 Exception 案例中。 这么多年前(我的第一个答案之一。)我不知道我在想什么。我只是希望它不为零。看起来我想保留该值,以便调用者可以看到代码是什么。但是我为什么要否定呢?这是一个谜。

以上是关于当未使用 Environment.Exit() 时,.net 程序可以具都有哪些退出代码?的主要内容,如果未能解决你的问题,请参考以下文章

在 Environment.Exit() 上捕获异常

Winforms:Application.Exit vs Environment.Exit vs Form.Close

为啥 Environment.Exit() 不再终止程序?

System.Environment.Exit(0) 不退出程序

Environment.Exit 和 Main 的简单返回 2 之间的区别

在 C# 中测试 Environment.Exit()