如何从包中设置“中断所有异常”

时间:2013-03-23 02:31:29

标签: .net visual-studio-2010 visual-studio visual-studio-debugging visual-studio-extensions

我想做一个扩展,以快速切换调试器中的CLR异常 我尝试了几种方法,但都不令人满意。

这是我已经尝试过的:

  1. ExceptionSettings.SetBreakWhenThrownMSDN
    这非常慢(见this Connect issue)。我已经尝试了问题“Toggle “Break when an exception is thrown.” using macro or keyboard shortcut”的方法,似乎都没有可靠的工作:在大多数情况下,只有顶级复选框被设置,并且在调试时实际上并没有中断异常。

  2. 调用DTE.ExecuteCommand("Debug.Exceptions")以显示该窗口,并在此之前调用SetWindowsHookExMSDN)在它出现之前拦截它(以便用户没有闪光) )。这似乎是可能的,因为我能够拦截消息并得到HWND。但它似乎很hacky并且窗口不容易正确操作(它有SysListView32与自定义复选框和SysTreeView32的奇怪组合。所以我将其作为最后的机会解决方案。

  3. 以某种方式获取托管代码IDebugEngine2MSDN)并在调试会话开始时调用IDebugEngine2.SetExceptionMSDN)。这似乎是可能的,但我在获取调试引擎时遇到问题。我尝试使用IVsLoader描述on MSDN forums的方法,但我很确定它给了我一个与调试会话无关的新实例。

    我在这里也问过这个问题:“Visual Studio: How to get IDebugEngine2 from VS Package (except IVsLoader)”,但没有得到解决方案。

    我尝试使用IVsDebugger.AdviseDebugEventCallbackMSDN)并传递IDebugEventCallback2MSDN)的实现,但我总是null为{{{} 1}}(也没有pEngine)。

    我得到IDebugEngineCreateEvent2(未记录?)并且可以从中获取IDebugSessionCreateEvent2,但是IDebugSession2调用总是给我SetException错误的参数,所以我可能会在这里丢失一些东西(从HRESULT调用引擎上的SetException给出了确定,但是没有用。)

  4. 是否有其他方法比那些方法更好或者我错过了现有方法?


    UPDATE /注:
    如果你发现这个问题是因为你想要一个更快的“Break on All Exceptions”,我已经从Visual Studio Gallery获得了免费扩展:Exception Breaker

1 个答案:

答案 0 :(得分:10)

自动化界面是不可能的。为了尝试使用它们来提高性能,我创建了一个从异常组到ExceptionSettings对象的缓存和到ExceptionSetting对象的异常名称。这允许我绕过ExceptionSettings.Item以快速查找调用SetBreakWhenThrown的各个异常,但遗憾的是SetBreakWhenThrown的内部实现包括调用参数的调用,这反过来会触发内部枚举困扰整个方法的过程。缓存比不使用宏的代码快4倍,但我们仍然在谈论将IDE挂起几分钟的代码...

注意:以下说明仅针对Visual Studio 2012进行了测试。

在反汇编视图中单步执行SetBreakWhenThrown,显示关键内部调用(验证后)为sdm::CDebugManager::SetException。事实证明,您投射到SVsShellDebugger的shell调试器(IVsDebugger)实现了IDebuggerInternal,它提供了对当前IDebugSession3的访问。在我打开解决方案之后但在开始调试之前,此属性为非null。

IDebuggerInternal debugger = Package.GetGlobalService(typeof(SVsShellDebugger)) as IDebuggerInternal;
IDebugSession3 session = debugger != null ? debugger.CurrentSession : null;

注意:IDebuggerInternal接口定义于:

Microsoft.VisualStudio.Debugger.Interop.Internal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

使用EnumSetExceptions返回的信息,我创建了一个成功改变CLR异常设置的结构!在抛出异常时,调用IDebugSession3.SetException 启用调试器暂停。

EXCEPTION_INFO[] exceptionInfo =
{
    new EXCEPTION_INFO()
    {
        bstrExceptionName = typeof(NullReferenceException).FullName,
        bstrProgramName = null,
        dwCode = 0,
        pProgram = null,
        guidType = VSConstants.DebugEnginesGuids.ManagedOnly_guid,
        dwState = enum_EXCEPTION_STATE.EXCEPTION_STOP_FIRST_CHANCE
            | enum_EXCEPTION_STATE.EXCEPTION_STOP_SECOND_CHANCE
            | enum_EXCEPTION_STATE.EXCEPTION_JUST_MY_CODE_SUPPORTED
            | enum_EXCEPTION_STATE.EXCEPTION_STOP_USER_FIRST_CHANCE
            | enum_EXCEPTION_STATE.EXCEPTION_STOP_USER_UNCAUGHT
    }
};
hr = session.SetException(exceptionInfo);

禁用调试器暂停,请改用IDebugSession3.RemoveSetException