【问题标题】:WindowsMobile: Application Exits after handling Exception from DialogFormWindowsMo​​bile:处理来自 DialogForm 的异常后应用程序退出
【发布时间】:2010-10-18 00:01:32
【问题描述】:

我有以下简单的场景:

带有Button的DialogForm,Button_click会抛出异常。

一个带有按钮和标签的 MainForm,在单击时,我在 Catch 块中显示了 DialogForm 的新实例。

如果我在常规 WinForms 中运行此设置,我可以按预期捕获异常。

如果我在 WinMobile 中运行它(我已经在 WM5 和 WM6 Pro 上进行了测试),我可以使用调试器看到输入了 Catch 块 但异常继续传播 并且应用程序死亡。

MainForm 中的代码如下所示:

try
{
   using (DialogForm frm = new DialogForm())
   {
     DialogResult r = frm.ShowDialog();
     label1.Text = r.ToString();
  }
}
catch (Exception ex)
{
  label1.Text = ex.Message;
}

编辑:

我进一步调查了一下,在这段代码和 Application.Run() 周围加上了一个 catch {} 块,但应用仍然退出。

显然它不是失控的异常,它被捕获和处理得很好。但在此操作之后,应用程序似乎执行了一个不需要的 Exit()。

【问题讨论】:

    标签: c# winforms exception windows-mobile


    【解决方案1】:

    修补后我发现了一些有用的东西:

    try {
      // show Dialog that Throws
    }
    catch (Exception ex) {
      label1.Text = ex.Message;
      Application.DoEvents();  // this solves it
    }
    

    赏金仍然对任何可以告诉我为什么 DoEvents() 是必要的人开放。

    【讨论】:

    • 你试过我的建议了吗?我很想知道它会如何影响执行。
    • 嗯,听起来像是多线程相关的东西。您是否明确使用线程?对话框中的按钮点击处理程序是否有异常处理?
    • 线程与它无关。当您调用 ShowDialog 时,会为该对话框设置一个单独的消息泵,并在那里处理所有内容。我敢打赌,异常会通过 PostMessage 封送回 UI 线程,直到发生某些事情导致该消息被发送
    • (cont'd) 那么异常没有被“处理”。 DoEvents 简单地包装了对 Translate 和 DispatchMessage 的调用,这会强制系统将顶部项目从泵中弹出(您的异常)并处理它。
    • 不敢相信我之前没有看到这个解决方案。它困扰了我好几个星期。谢谢。
    【解决方案2】:

    您需要“DoEvents”的原因是它会在表单仍然可用时清除消息队列。

    发生的情况是,仍有消息等待针对引发异常的表单进行处理。通过在此处调用“DoEvents”,您可以在 using 块清理表单并停止处理队列上的消息之前处理它们。

    【讨论】:

    • 您对消息队列的看法可能是正确的,但 DoEvents 在 using-block 之外。
    • 它看起来只是在 using 块之外。将在清理表单对象之前评估 catch 块。这是合乎逻辑的,因为您可能需要从 catch 块评估 using 块中的对象。
    • @Stevo3000 - 是的,执行顺序是因为我们声明它先尝试然后捕获,然后最后捕获。使用最终扩展到尝试 - 所以你得到了这种行为。无论如何,我怀疑你会在 Win32 上看到这个。也许是 CF 错误?
    • @Jonathan - 这很可能归结为消息泵的基本原理在 CF 中的工作方式,而不是实际的错误。
    【解决方案3】:

    我能找到的最好的信息是您正在调用 ShowDialog()。

    我尝试使用 Reflector,但它不能处理 CF dll。所以最好的比较是看主要的非CF文件。在其中,如果您跟踪 ShowDialog() 函数,它最终会调用 Application.RunDialog(form)。在那里,它创建一个新的线程上下文并为对话窗口运行它自己的消息循环。

    由于我无法查看实际的 CF DLL,我只能进行“有根据的猜测”。这似乎与异常发生在单独的消息循环中并且不会被正确捕获的事实有关,除非您通过 DoEvents() 处理应用程序的消息队列。

    所以基本上,ShowDialog() 会导致在单独的消息循环中创建异常,并且除非您调用 DoEvents(),否则无法正确处理它被捕获的事实。

    如果你尝试一个常规的 Show() 会发生什么?你还需要 DoEvents 吗?我没有测试这个的环境,所以我只能建议你尝试一下。如果您将其更改为 Show() 并且不再需要 DoEvents(),我认为我们将确定我是否正确。

    【讨论】:

    • 如果我做一个常规的 Show 我不能用 try/catch 包围它,也不能等待响应。 Show 的异常处理完全不同。我还没有尝试过,但我完全希望应用程序退出,因为它应该退出。
    【解决方案4】:

    https://connect.microsoft.com/VisualStudio/feedback/details/94356/modal-windows-in-net-compact-framework-application-stop-working-if-unhandled-exception-on-modal-dialog-is-raised#tabs

    在紧凑框架 2.0 中,这是一个公认的问题... 他们不在乎……

    如果您在捕获异常后在 try 中使用 showdialog,则 showdialog 不再起作用....

    【讨论】:

    • 罗伯托,感谢链接。我在那里发布了自己的答案作为解决方法。我不再期望 CF2 有任何修复...
    【解决方案5】:

    虽然编程文档会声明以下构造是不必要的,但我发现有时我必须使用以下构造。

    try
    {
     using (DialogForm frm = new DialogForm())   
     {     
           DialogResult r = frm.ShowDialog();
           label1.Text = r.ToString();  
     }
    }
    catch (Exception ex)
    {
        label1.Text = ex.Message;
    }
    catch
    {
        label1.Text = "Unknown Exception";
    }
    

    【讨论】:

      【解决方案6】:

      也许挂钩 AppDomain.CurrentDomain.UnhandledException(连同 Joel 的提示)可以解决您的异常问题?可能类似于this other .NET answer

      我使用下面的代码

          try
          {
              AppDomain.CurrentDomain.UnhandledException +=
                  (object sender, UnhandledExceptionEventArgs e) =>
                  {
                      CrashOn((Exception)e.ExceptionObject, e.IsTerminating);
                  };
              var mainWindow = new MainWindow();
              MobileDevice.Hibernate += (sender, e) => { mainWindow.Hibernate(); };
              Application.Run(mainWindow);
          }
          catch (Exception huh)
          {
              CrashOn(huh, false);
          }
      

      在我的WM6 Professional twitter clientProgram.Main() 中。这里CrashOn() 方法将异常信息保存到磁盘并启动崩溃恢复可执行文件。然后,这会显示客户端崩溃的信息,可以选择将异常信息邮寄给我,并提供退出或重新启动客户端的选项。

      【讨论】:

      • 一个有用的例子,但我已经添加了这个并且程序没有进入 CrashOn。请注意,我已经编辑了问题和标题。
      【解决方案7】:

      根据其他答案和我对所需 DoEvents 的评论:您是否尝试检查您的原始 catch 语句 label1.InvokeRequired 是否可能是 true

      如果是这样,您可能会在这里遇到某种与多线程相关的竞争条件,因为您将 label1.Text 设置为从另一个线程抛出的异常类的属性?

      在常规的 .NET 1.0 中,这通常只是起作用,而它不应该起作用。在更高版本中,忽略 InvokeRequired == true 会导致异常。我不确定紧凑框架如何处理这种“违规行为”。也许它只是存在这个过程呢?

      【讨论】:

      • 一个有用的建议,但不是答案,在 catch 块中 InvokeRequired 为 false。我已将问题简化为问题中描述的非常小的应用程序,没有线程等。只有 2 个表单和 2 个按钮。
      【解决方案8】:

      我记得 dot net 有一个默认的异常处理程序,当异常跨越特定边界时会触发该处理程序。正是这个处理程序导致您的应用程序退出。我记得一段时间前看过这个问题,但不幸的是不再可以访问代码。至于 .NET 和 .NET CF 之间的行为差​​异,这是因为两者处理帧的方式不同(可能 CF 中的帧没有父级或类似的东西)。

      你可以加入这个默认的异常处理并做任何你想做的事......我认为我实现的代码是这样的:Unhandled Exceptions

      【讨论】:

      • 唉,CF 中的 Application 类没有 ThreadException 或任何其他事件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      • 2010-10-10
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多