3

我使用此代码来捕获 WinForm 应用程序 UnhandledException。

[STAThread]
static void Main(string[] args)
{
    // Add the event handler for handling UI thread exceptions to the event.
    Application.ThreadException += new
      System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

    // Set the unhandled exception mode to force all Windows Forms errors 
    // to go through our handler.
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

    // Add the event handler for handling non-UI thread exceptions to the event. 
    AppDomain.CurrentDomain.UnhandledException += 
        new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    try
    {
        Application.Run(new MainForm());
    } catch....

在那里我将尝试重新启动应用程序。现在我的问题是模拟这样的异常。我在尝试之前尝试过(主要):throw new NullReferenceException("test");VS抓住了它。

在 MainForm 代码中也尝试了 button :

    private void button1_Click(object sender, EventArgs ev)
    {         
        ThreadPool.QueueUserWorkItem(new WaitCallback(TestMe), null);
    }

    protected void TestMe(object state)
    {
        string s = state.ToString();
    }

没有帮助,VS 抓住了它,即使在发布模式下也是如此。

  • 最后,我应该如何强制应用程序生成UnhandleldException
  • 我可以重新启动应用程序CurrentDomain_UnhandledException吗?
  • 我怎样才能生成一个ThreadException

PS。

如果我在 VS 之外启动一个 Windows 通用窗口

应用程序 MyApplication”遇到错误,应关闭...blabla...发送报告/不发送。

但是,我希望 VS 输入此方法(...Domain_Unhahdled...)

编辑:重新启动应用程序时,是否可以禁用 Windows 崩溃消息,如下所示: alt text http://byfiles.storage.msn.com/y1pOhWnAAXfMYtJH2VNa5iL0l1hjAqNHD2VmVnl8nN6L1oQC_xHkyHCJxhMc1ZLxLOH9ZXfZoo5zX8?PARTNER=WRITER

代码:

static void CurrentDomain_UnhandledException(object sender, 
    UnhandledExceptionEventArgs e)
{
    // Since we can't prevent the app from terminating
    // log this to the event log.
    Logger.LogMessage(ERROR, errorMsg);
    Application.Restart();
4

2 回答 2

6

我仍然不完全确定我理解这个问题,但有几点要提:

  • Application.ThreadException并且Application.SetUnhandledExceptionMode仅适用于 Windows 窗体线程。任意ThreadPool线程实际上不是 Windows 窗体线程,即使在 Winforms 应用程序中也是如此,因此这两行代码是无效的。

  • 注册一个事件AppDomain.CurrentDomain.UnhandledException 捕获ThreadPool线程上发生的异常。

  • 但是,该UnhandledException事件实际上无法处理异常。到那时,阻止进程终止已经太晚了,如果后台线程上发生异常,这种情况总是会发生(除非您启用了旧的 .NET 1.1 行为,但是......不要。)此事件是真的只适合记录或清理。

我自己使用与您类似的测试代码对此进行了测试,并验证了异常“处理程序”中的代码确实执行了。但是该应用程序仍然会崩溃,并且您无法停止它。

更新:我将再做一次尝试,就是这样。

如果您的目标是让无人值守的应用程序始终运行,那么您有以下三种选择:

  1. 正确处理您的异常。到目前为止,这是最好的,也可能是唯一正确的解决方案。挂钩AppDomain.UnhandledException处理异常。当控件进入该事件处理程序时,您的应用程序已经崩溃。你不能再保存它了。

    从后台线程转义的未处理异常是您需要修复的代码中的灾难性错误。从后台线程转义的未处理异常是您需要修复的代码中的灾难性错误。从后台线程转义的未处理异常是您需要修复的代码中的灾难性错误。 请不要再评论“我不在乎”的效果——你需要开始关心。

  2. 礼貌地要求 Windows为您重新启动应用程序。 与尝试从崩溃处理程序重新启动不同,这是一个非常糟糕的主意,原因太多而无法完全枚举(数据损坏、无限重启循环、资源泄漏、操作系统不稳定等),注册重新启动实际上允许这种情况发生在一种半可控的时尚。正如我在评论中提到的,在 .NET 中与此 API 进行互操作非常简单。您在应用程序启动时立即注册,而不是在应用程序崩溃并且您的应用程序处于不受信任状态时注册。

  3. 创建一个监视您的应用程序并在它崩溃时重新启动它的主管服务。由于前两点中讨论的许多原因,这仍然很糟糕,但您至少有一定程度的稳定战斗机会。

    您可以通过使用命名互斥体、在主管中等待它并观察WAIT_ABANDONED状态(AbandonedMutexException在 .NET 中)来获得应用程序崩溃的非常可靠的指示。放弃状态仅在拥有互斥锁的进程终止但未释放它时出现 - 即有未处理的异常。通过更多的互操作黑客攻击,您还可以检测并关闭崩溃窗口。

这些是你的选择。我强烈建议您在后台线程上处理异常,因为从后台线程逃逸的未处理异常是您需要修复的代码中的灾难性错误。 如果它来自外部组件并且您无法捕获它,那么灾难性错误就在该组件中,您应该考虑将其报告给作者或使用不同的组件。

如果应用程序不够稳定而无法真正继续运行,那么简单地要求“此应用程序必须始终运行并且应该完全忽略致命崩溃”并不能实现这种情况。崩溃就是崩溃。如果发动机突然熄火,您不会设计一辆汽车就立即重新启动。您能做的最好的事情就是让受信任的操作员(无论是人工操作员、操作系统还是某些监控软件)代表它重新启动应用程序。

这个问题的变体似乎经常出现——基本上,“我的应用程序不应该崩溃,或者如果它崩溃了,它应该是不可见的。我想吃掉每一个未处理的异常并假装它没有发生。” 这不仅是不可能的,而且与几乎所有优秀设计的原则背道而驰(尤其是“快速失败”原则,当然可以重新解释,但绝不能完全忽略)。

这就是我能说的。如果您不愿意接受其中任何一个,那么祝您找到可行的替代方案。

于 2010-05-19T00:14:12.307 回答
0

Visual Studio 可能设置为中断异常,但如果您继续单步执行代码,它仍应遵循您想要的路径。您还应该尝试在 VS 之外运行该应用程序。

在未处理的异常之后重新启动应用程序是一个坏主意,因为您(根据定义)处于未知状态。如果异常条件从未改变,重新启动,如果可能的话,可能会使您进入一个永无止境的重新启动循环。相反,请考虑尝试将异常信息记录到 Web 服务器,以便调查和修复崩溃。不过,请务必在上传崩溃数据之前获得用户的许可。

于 2010-05-18T22:18:02.853 回答