【问题标题】:C# Application fails silently when exception is thrown抛出异常时 C# 应用程序静默失败
【发布时间】:2018-01-14 12:01:35
【问题描述】:

我制作了一个在启动时抛出异常的小型 winforms 应用程序:

static void Main()
{
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  throw new Exception("lol");
  Application.Run(new Form1());
}

当我从调试器运行它时,会抛出我所期望的异常。如果我浏览到 bin 目录中的可执行文件并从资源管理器中运行,则应用程序会静默失败,甚至不会显示“此应用程序已崩溃对话框”。

我确实在事件查看器中记录了异常:

Application: WindowsFormsApplication1.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Exception
   at WindowsFormsApplication1.Program.Main()

但这并不是很大的帮助!

这发生在一堆应用程序中,我觉得我有一些系统范围的设置抑制了这个系统对话框,但我不知道它可能是什么!任何指导将不胜感激。

【问题讨论】:

    标签: c# debugging exception exception-handling


    【解决方案1】:

    据我了解,WinForms 应用程序仅在启动时

    Application.Run(new Form1());
    

    调用。它没有控制台输出,它会尝试通过 WinForms UI 告诉你一切。但目前它还没有。

    如果您希望应用程序显示任何内容,则必须确保消息循环已启动。因此,如果您想在应用程序启动时立即抛出异常,请覆盖表单的 OnLoad 方法并在那里抛出异常。 (我将代码从 Program.cs 移动到表单的代码隐藏)

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
                throw new ApplicationException("ASDF");
            }
    
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                //AllocConsole();
                //Console.WriteLine("BOOO");
                //throw new ApplicationException("BOOOO");
                Application.Run(new Form1());
            }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool AllocConsole();
    
        }
    }
    

    这应该会为您提供一个“不错的”异常窗口。

    或者编写一个控制台应用程序。 :)

    如果必须,可以尝试分配一个控制台输出:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                AllocConsole();
                Console.WriteLine("BOOO");
                throw new ApplicationException("BOOOO");
                Application.Run(new Form1());
            }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool AllocConsole();
        }
    }
    

    但是恕我直言,让应用程序启动,然后在它应该使用的 UI 上处理问题,将是更简洁的方法。

    【讨论】:

    • 我只是尝试将异常移动到表单的 OnLoad() 函数中,得到了相同的结果(即在没有附加调试器时没有通知发生异常)
    • 有趣。我为最重要的解决方案添加了更多代码。它给了我一个例外窗口。请将其与您所做的进行比较。
    • 有趣。我最初将异常放在 OnLoad 的事件处理程序中,然后我尝试像您一样覆盖 OnLoad()。两种情况都没有快乐。我刚刚尝试将异常放在表单的 OnClick() 处理程序中,并且 DID 显示系统对话框,所以我认为您对消息队列等的预感是正确的......
    • 重点是,你必须确保你的 UI 已经设置好,所以如果你想在 windows 窗体应用程序启动之前显示错误,你要么必须使用MessageBox.Show() 要么获取与AllocConsole 类似的控制台输出。但最好不要在 Windows 消息循环开始之前抛出异常。此外,处理异常并提供一个适当的 UI 来解释问题,不要依赖 WinForms 默认设置的那个(这只会给人一种应用程序损坏的印象)。
    • 对我来说,关键是在 UI 启动后将所有程序代码移动到。我在 Program.Main() 中进行了一些初始化,但我会将其移至其他地方并(懒惰地?)在表单启动后进行初始化。我很欣赏正确的代码应该很好地处理异常,但这仍处于开发的早期阶段,我花了很长时间试图弄清楚为什么当其他人在没有任何线索的情况下测试它时它“只是不起作用”它什么都做。为了以防万一,我觉得将每个函数都包装在 try 块中很脏!
    【解决方案2】:

    尝试处理 appdomain 未处理的异常事件。

      public static void Main()
      {
       AppDomain currentDomain = AppDomain.CurrentDomain;
       currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
      }
    
      static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
      {
       Exception e = (Exception) args.ExceptionObject;
       Console.WriteLine("MyHandler caught : " + e.Message);
       Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
      }
    

    https://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception(v=vs.110).aspx

    【讨论】:

    • 我确实尝试过这个,但不幸的是没有帮助。从 ClickOnce 开始菜单快捷方式运行时,它似乎也产生了自己的安全异常,所以我放弃了它,因为我不想再掉下去了:)
    猜你喜欢
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    相关资源
    最近更新 更多