WPF程序启动崩溃:如何调试?

7

我有一个WPF程序,在开发PC和客户端PC1上运行正常。但是在客户端PC2上启动时立即崩溃并弹出“将报告发送给Microsoft”窗口。我希望能得到一些关于如何追踪问题的建议。以下是我尝试过的方法:

  1. Inserted try-catch in my main window class:

    public MainWindow()
    {
      try
      {
         MessageBox.Show("Before InitComp()");
         InitializeComponent();
         MessageBox.Show("Before Sub1()");
         Subroutine1();
         MessageBox.Show("Before Sub2()");
         Subroutine2();
         ... etc ...
      }
      catch (Exception ex)
      {  ... code for MessageBox display error here ... }
    }
    
想要解决问题,需要先找出启动序列的哪个部分出了问题,然而第一个调试信息“Before InitComp()”甚至没有出现。因此似乎应用程序在启动我的代码之前就崩溃了。
以下是解决方法:
1. 可以在客户端PC 2上安装整个VS2008,在源代码中加载并使用IDE Debugger跟踪问题。这可能是最有效的查找问题的方法。但我不想这样做,因为a)客户端PC 2不属于我, b)它不具有可扩展性:我必须对客户端PC 3/4/5/...进行相同的操作,并且c)它违反了我们公司的VS2008许可证。
如何解决这个问题呢?

在Application_UnHandledException事件处理程序中,您遇到了什么错误?如果方法的catch块没有捕获它,全局处理程序应该会捕获。 - Scott Wylie
谢谢,我之前不知道有Application_UnHandledException事件处理程序。我会尝试一下并看看效果。 - David Ong
终于找到问题所在了:应用程序使用了需要 .Net 3.5 SP1 的 WPF 工具包。客户端 PC 2 只有 .Net 3.5。安装了 SP1 和 WPF 工具包后,应用程序现在可以正常运行了。感谢 Scott 和 Pinzon 的建议。谢谢大家! - David Ong
很高兴你解决了问题。你在客户端机器上直接安装了WPF工具包吗?你不想在部署中只包含它的DLL文件吗? - Scott Wylie
Scott:将DLL打包是正确的方式,但我们还没有这样做。目前的分发方式非常原始,主要是因为我们只有10个用户。我希望最终能改进我们的分发流程。 - David Ong
4个回答

8
在您的App.xaml头部添加以下内容:
<Application DispatcherUnhandledException="App_DispatcherUnhandledException" />

在您的App.xaml.cs中添加类似以下代码:

    void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs args)
    {
        log.Fatal("An unexpected application exception occurred", args.Exception);

        MessageBox.Show("An unexpected exception has occurred. Shutting down the application. Please check the log file for more details.");

        // Prevent default unhandled exception processing
        args.Handled = true;

        Environment.Exit(0);
    }

什么是日志?它并不存在。我该如何创建它? - eric.itzhak

7

传统方法:像这样的硬性崩溃可能会在Windows的事件查看器中显示出来。你已经检查过那里了吗?很多时候,这可以告诉我答案而不需要额外的麻烦。


2

下载ProcDump。运行procdump -t -w app.exe ...或者可能是procdump -e -w app.exe ...。同时探索其他标志。然后在您喜欢的调试器(Visual Studio/WinDbg)中打开转储文件并查看堆栈跟踪。


谢谢你提供关于ProcDump的提示。对于程序员来说,这是一个很好的工具。 - David Ong

1

追踪/日志记录在客户遇到问题时非常有用。您并不总是能够进行调试,而且转储可能无法提供导致该点的完整视图。它绝对可以补充转储或调试。

您还可以打开和关闭它,甚至切换级别。

DebugView是一个捕获跟踪的好程序:

http://technet.microsoft.com/en-us/sysinternals/bb896647

追踪:

http://msdn.microsoft.com/en-us/library/3at424ac.aspx

例如,这是一个带有可切换级别的示例跟踪类:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.Threading;

namespace Sample
{
    public class Tracer
    {
        //
        // supports holding many trace switches.
        //
        static Dictionary<string, TraceSwitch> s_switches = new Dictionary<string, TraceSwitch>();
        static TraceSwitch s_switch = new TraceSwitch("trace", "Default tracing switch");
        static object s_locker = new object();

        private static TraceSwitch GetSwitch (string category)
        {
            // only pay the lock penalty if it doesn't exist
            if (!s_switches.ContainsKey (category))
            {
                lock (s_locker)
                {
                    if (!s_switches.ContainsKey (category))
                    {
                        TraceSwitch traceSwitch = new TraceSwitch(category,
                                    String.Format("Tracing switch for category '{0}'", category));
                        s_switches.Add (category, traceSwitch);
                    }
                }
            }

            return s_switches[category];
        }

        //
        // No level overloads
        //
        public static void Output(string message)
        {
            WriteLine("None", TraceLevel.Info, message);
        }

        public static void OutputIf(bool condition, string message)
        {
            if (condition)
            {
                Output(message);
            }
        }

        public static void Output(string format, params object[] args)
        {
            Debug.Assert(format != null);
            Output(string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void OutputIf(bool condition, string format, params object[] args)
        {
            if (condition)
            {
                Output(format, args);
            }
        }

        //
        // Error level overloads
        //
        public static void Error(string message)
        {
            if (s_switch.TraceError)
            {
                WriteLine(String.Empty, TraceLevel.Error, message);
            }
        }

        public static void Error(string category, string message)
        {
            if (GetSwitch(category).TraceError)
            {
                WriteLine(category, TraceLevel.Error, message);
            }
        }

        public static void ErrorIf(bool condition, string message)
        {
            if (condition)
            {
                Error(message);
            }
        }

        public static void ErrorIf(string category, bool condition, string message)
        {
            if (condition)
            {
                Error(category, message);
            }
        }

        public static void Error(string format, params object[] args)
        {
            Debug.Assert(format != null);
            Error(string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void Error(string category, string format, params object[] args)
        {
            Debug.Assert(format != null);
            Error(category, string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void ErrorIf(bool condition, string format, params object[] args)
        {
            if (condition)
            {
                Error(format, args);
            }
        }

        public static void ErrorIf(string category,
                                   bool condition,
                                   string format,
                                   params object[] args)
        {
            if (condition)
            {
                Error(category, format, args);
            }
        }

        //
        // Warning level overloads
        //
        public static void Warning(string message)
        {
            if (s_switch.TraceWarning)
            {
                WriteLine(String.Empty, TraceLevel.Warning, message);
            }
        }

        public static void Warning(string category, string message)
        {
            if (GetSwitch(category).TraceWarning)
            {
                WriteLine(category, TraceLevel.Warning, message);
            }
        }

        public static void WarningIf(bool condition, string message)
        {
            if (condition)
            {
                Warning(message);
            }
        }

        public static void WarningIf(string category, bool condition, string message)
        {
            if (condition)
            {
                Warning(category, message);
            }
        }

        public static void Warning(string format, params object[] args)
        {
            Debug.Assert(format != null);
            Warning(string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void Warning(string category, string format, params object[] args)
        {
            Debug.Assert(format != null);
            Warning(category, string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void WarningIf(bool condition, string format, params object[] args)
        {
            if (condition)
            {
                Warning(format, args);
            }
        }

        public static void WarningIf(string category,
                                     bool condition,
                                     string format,
                                     params object[] args)
        {
            if (condition)
            {
                Warning(category, format, args);
            }
        }

        //
        // Info level overloads
        //
        public static void Info(string message)
        {
            if (s_switch.TraceInfo)
            {
                WriteLine(String.Empty, TraceLevel.Info, message);
            }
        }

        public static void Info(string category, string message)
        {
            if (GetSwitch(category).TraceInfo)
            {
                WriteLine(category, TraceLevel.Info, message);
            }
        }

        public static void InfoIf(bool condition, string message)
        {
            if (condition)
            {
                Info(message);
            }
        }

        public static void InfoIf(string category, bool condition, string message)
        {
            if (condition)
            {
                Info(category, message);
            }
        }

        public static void Info(string format, params object[] args)
        {
            Debug.Assert(format != null);
            Info(string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void Info(string category, string format, params object[] args)
        {
            Debug.Assert(format != null);
            Info(category, string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void InfoIf(bool condition, string format, params object[] args)
        {
            if (condition)
            {
                Info(format, args);
            }
        }

        public static void InfoIf(string category,
                                  bool condition,
                                  string format,
                                  params object[] args)
        {
            if (condition)
            {
                Info(category, format, args);
            }
        }

        //
        // Verbose level overloads
        //
        public static void Verbose(string message)
        {
            try
            {
                if (s_switch.TraceVerbose)
                {
                    WriteLine(String.Empty, TraceLevel.Verbose, message);
                }
            }catch{}
        }

        public static void Verbose(string category, string message)
        {
            if (GetSwitch(category).TraceVerbose)
            {
                WriteLine(category, TraceLevel.Verbose, message);
            }
        }

        public static void VerboseIf(bool condition, string message)
        {
            if (condition)
            {
                Verbose(message);
            }
        }

        public static void VerboseIf(string category, bool condition, string message)
        {
            if (condition)
            {
                Verbose(category, message);
            }
        }

        public static void Verbose(string format, params object[] args)
        {
            Debug.Assert(format != null);
            Verbose(string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void Verbose(string category, string format, params object[] args)
        {
            Debug.Assert(format != null);
            Verbose(category, string.Format(CultureInfo.InvariantCulture, format, args));
        }

        public static void VerboseIf(bool condition, string format, params object[] args)
        {
            if (condition)
            {
                Verbose(format, args);
            }
        }

        public static void VerboseIf(string category,
                                     bool condition,
                                     string format,
                                     params object[] args)
        {
            if (condition)
            {
                Verbose(category, format, args);
            }
        }

        //
        // Trace Output Format:
        // [category:level]PID|ThreadID|08:16:15.134| message.
        //
        private static void WriteLine(string category,
                                      System.Diagnostics.TraceLevel level,
                                      string message)
        {
            Debug.Assert(message != null);

            string traceLine = string.Format(
                CultureInfo.InvariantCulture,
                "[{0}:{1}]{2}|{3}|{4:HH}:{4:mm}:{4:ss}.{4:fff}|{5}",
                category,
                level.ToString(),
                Process.GetCurrentProcess().Id,
                Thread.CurrentThread.ManagedThreadId,
                DateTime.Now,
                message);

            Trace.WriteLine(traceLine);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接