如何获取有关异常的更多信息

7

我在Windows 7(64位)上使用Visual Studio 2008创建了一个解决方案。

它能够正常工作。

但是,当我将它移动到另一台也是Windows 7(64位)的计算机上时,它几乎没有提供任何信息就崩溃了。

最初的问题是:

被调用方拒绝了调用

我随后实现了这个解决方案:

如何正确地使用GetTypeFromProgID来获取Visual Studio 2008

然而,现在我的问题是,当我在另一台计算机上运行可执行文件时,程序会立即崩溃,并显示以下信息:

Description:
  Stopped working

Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: EmailSalesVolumeSolution.exe
  Application Version:  1.0.0.0
  Application Timestamp:    508064dd
  Fault Module Name:    KERNELBASE.dll
  Fault Module Version: 6.1.7601.17932
  Fault Module Timestamp:   503285c2
  Exception Code:   e0434f4d
  Exception Offset: 000000000000caed
  OS Version:   6.1.7601.2.1.0.256.48
  Locale ID:    1033

Read our privacy statement online:
  http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0409

If the online privacy statement is not available, please read our privacy statement offline:
  C:\Windows\system32\en-US\erofflps.txt

我在代码中添加了 try/catch 语句,但仍然未能得到正确的错误消息:

static void Main()
{
    try
    {
        EnvDTE80.DTE2 dte;
        object obj = null;
        System.Type t = null;

        // Get the ProgID for DTE 8.0.
        t = System.Type.GetTypeFromProgID("VisualStudio.DTE.9.0",
          true);
        // Create a new instance of the IDE.
        obj = System.Activator.CreateInstance(t, true);
        // Cast the instance to DTE2 and assign to variable dte.
        dte = (EnvDTE80.DTE2)obj;

        // Register the IOleMessageFilter to handle any threading
        // errors.
        MessageFilter.Register();
        // Display the Visual Studio IDE.
        dte.MainWindow.Activate();


        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.Run(new Form1());

        // For example, get a reference to the solution2 object
        // and do what you like with it.

        // All done, so shut down the IDE...
        dte.Quit();
        // and turn off the IOleMessageFilter.
        MessageFilter.Revoke();

    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }
}

我该如何确定异常发生的确切位置以及异常是什么?

我有一些非托管代码:

using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE;
using EnvDTE80;
using EnvDTE90;
using System.Runtime.InteropServices;

namespace EmailSalesVolumeSolution
{
    public class MessageFilter : IOleMessageFilter
    {
        //
        // Class containing the IOleMessageFilter
        // thread error-handling functions.

        // Start the filter.
        public static void Register()
        {
            IOleMessageFilter newFilter = new MessageFilter();
            IOleMessageFilter oldFilter = null;
            CoRegisterMessageFilter(newFilter, out oldFilter);
        }

        // Done with the filter, close it.
        public static void Revoke()
        {
            IOleMessageFilter oldFilter = null;
            CoRegisterMessageFilter(null, out oldFilter);
        }

        //
        // IOleMessageFilter functions.
        // Handle incoming thread requests.
        int IOleMessageFilter.HandleInComingCall(int dwCallType,
          System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr
          lpInterfaceInfo)
        {
            //Return the flag SERVERCALL_ISHANDLED.
            return 0;
        }

        // Thread call was rejected, so try again.
        int IOleMessageFilter.RetryRejectedCall(System.IntPtr
          hTaskCallee, int dwTickCount, int dwRejectType)
        {
            if (dwRejectType == 2)
            // flag = SERVERCALL_RETRYLATER.
            {
                // Retry the thread call immediately if return >=0 & 
                // <100.
                return 99;
            }
            // Too busy; cancel call.
            return -1;
        }

        int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee,
          int dwTickCount, int dwPendingType)
        {
            //Return the flag PENDINGMSG_WAITDEFPROCESS.
            return 2;
        }

        // Implement the IOleMessageFilter interface.
        [DllImport("Ole32.dll")]
        private static extern int
          CoRegisterMessageFilter(IOleMessageFilter newFilter, out 
          IOleMessageFilter oldFilter);
    }
    [ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    interface IOleMessageFilter
    {
        [PreserveSig]
        int HandleInComingCall(
            int dwCallType,
            IntPtr hTaskCaller,
            int dwTickCount,
            IntPtr lpInterfaceInfo);

        [PreserveSig]
        int RetryRejectedCall(
            IntPtr hTaskCallee,
            int dwTickCount,
            int dwRejectType);

        [PreserveSig]
        int MessagePending(
            IntPtr hTaskCallee,
            int dwTickCount,
            int dwPendingType);
    }
}

在我遇到问题的机器上安装了VS 2008 express之后,现在出现了这个问题:

enter image description here


你能在附加调试器后指出特定的行吗? - Danpe
4个回答

2
尝试从异常中打印更多信息:
catch(Exception e)
{
    MessageBox.Show(e.Message + ":\n" + e.StackTrace);
}

您可以使用这个来捕获所有内部异常:
string except = "Uncaught Exception: ";
while(e != null)
{
    except += e.Message + ";\n";
    e = e.InnerException;
}

如果程序崩溃且没有异常,那么您需要尝试附加调试器。
您需要在计算机上安装Visual Studio或者能够使用远程桌面进行远程调试。如何附加到正在运行的进程 附加到正在运行的进程:
在“调试”菜单中,选择“附加到进程”。
在“附加到进程”对话框中,从“可用进程”列表中找到要附加到的程序。
如果要调试的程序在另一台计算机上运行,请使用“限定符”列表框选择远程计算机。有关详细信息,请参阅“How to: Select a Remote Machine”。
如果该进程在不同的用户帐户下运行,请选择“显示所有用户的进程”复选框。
如果您通过远程桌面连接连接,请选择“显示所有会话中的进程”复选框。
在“附加到”框中,确保列出了要调试的代码类型。默认设置“自动”尝试确定您要调试的代码类型。如果自动设置不合适:
点击“选择”。
在“选择代码类型”对话框中,点击“调试这些代码类型”,并选择要调试的类型。
点击“确定”。
点击“附加”。 注意:必须以DEBUG模式编译可执行文件。

更新

我看到你使用了需要.NET 4.5Type.GetTypeFromProgID,请确保安装了.NET 4.5在出现错误的电脑上!

似乎t = System.Type.GetTypeFromProgID("VisualStudio.DTE.9.0", true);引发了COMException,这意味着在其他电脑上未注册"VisualStudio.DTE.9.0"。

你应该将Microsoft Visual Studio 2008 DTE作为你的程序依赖项添加。


尝试附加调试器以查看哪一行崩溃。 - Danpe
1
顺便提一下,e.ToString()会给出完整的异常消息和堆栈跟踪。 - Sklivvz
非常感谢。我现在正在下载VS 2008 Express。 - Alex Gordon
我该如何将VS 9 DTE添加为依赖项? - Alex Gordon
我不知道你是如何安装你的应用程序的,但考虑使用InstallSheild或阅读这篇文章:https://dev59.com/3WTWa4cB1Zd3GeqPH-lm。 - Danpe
显示剩余4条评论

2

你也可以尝试订阅 AppDomain.CurrentDomain.UnhandledException 事件:

AppDomain.CurrentDomain.UnhandledException += 
      (sender, e) => MessageBox.Show(e.ExceptionObject.ToString());

Main方法的顶部执行此操作。

谢谢,我刚刚尝试了这个,但仍然得到相同的结果。 - Alex Gordon
如果您在另一台机器上安装了Visual Studio,则可以添加“Debugger.Break”命令以在调试器中浏览代码。顺便问一下,您的应用程序中是否有一些非托管代码调用? - Sergey Berezovskiy
谢谢。我认为我有未托管的代码(我不知道那是什么,但我已经复制粘贴了它)。 - Alex Gordon
尝试在您的try ... catch块中添加一个没有参数的catch,catch { MessageBox.Show("Non-CLS compliant exception caught."); }。至少我们会知道我们有非CLS异常。 - Sergey Berezovskiy

1

您的 DLL 可能未在客户端计算机上注册。检查您调用 COM 对象的 DLL,并在管理员命令提示符中执行 Regsvr32 YouComDllName.dll(右键单击命令提示符图标并选择 以管理员身份运行)。根据您使用的是 32 位还是 64 位应用程序,您可能需要使用 C:\Windows\System32C:\Windows\SysWOW64 中的 Regsvr32 副本(反过来,64 位版本在 system32 中,而 32 位版本在 SysWOW64 中)。


如果在您的计算机上仅注册DLL无法正常工作,请在计算机上运行Dependancy Walker程序。当您获取到程序所需的所有DLL时,请检查客户端计算机是否缺少任何DLL。您调用的DLL可能存在,但它所依赖的DLL可能不存在。

1
Dependancy Walker 可以显示出你缺少哪个 DLL,只需将其在你的计算机上给出的列表与其他计算机上的列表进行比较即可。确保在运行 Dependancy Walker 时进行“Profile->Start Profiling”,因为它不会捕获延迟绑定的 DLL,例如你的 COM DLL,直到你在分析器中运行它。 - Scott Chamberlain
Scott,我还在等待用户注销机器,以便我可以操作它。但是,考虑到它在两台没有完整版Visual Studio安装的计算机上无法工作,而在我的计算机上(已安装完整版VS)却可以工作,你认为这是否是问题所在? - Alex Gordon
我认为这很不可能。更有可能的是,您的代码依赖于第三方DLL,该DLL与VS无关,已安装在您的计算机上,但未安装在客户端的计算机上。(如果您的程序所依赖的DLL也是在您的计算机上使用VS编写(或至少编译一次),我知道它会自动注册DLL以进行测试,如果您设置了某些设置,那可能就是它被注册的方式)。或者可能是您在安装程序.msi上选中的复选框,而您的客户端没有选中(例如:SQL SDK随SQL Server一起提供,但是是可选安装)。 - Scott Chamberlain
非常感谢Scott在这方面给了我这么多帮助。这个软件没有安装程序,我只是把整个DEBUG文件夹复制到另一台机器上。 - Alex Gordon

0
唯一有效的解决方案是安装Visual Studio。一旦安装完成,我就得到了确切的异常信息。

只是提醒一下,APPCRASH和KERNELBASE.dll故障模块意味着在KERNELBASE.dll内部抛出了异常。在C#中,这通常意味着您的Interop调用之一存在问题。就我个人而言,由于方法签名中的拼写错误,我曾经遇到过这种情况。从您在Visual Studio中获得的错误截图来看,可能是您的com对象的无效GUID(可能未注册)。 - Scott Chamberlain
非常感谢您的建议!即使这在我的计算机上运行,但在另一台计算机上不行,这种情况仍然是正确的吗? - Alex Gordon
您的DLL可能未在客户端机器上注册。检查您调用COM对象的DLL,并以管理员身份运行Regsvr32 YouComDllName.dll。根据您使用的是32位还是64位应用程序,您可能需要使用C:\Windows\System32C:\Windows\SysWOW64中的Regsvr32副本(反过来,64位版本位于system32中,而32位版本位于SysWOW64中)。 - Scott Chamberlain
@Danpe,请问确切的解决方案是什么?请给我一些建议。 - Pramod Gehlot

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