19

我想进行扩展以在调试器中快速切换 CLR 异常的中断。
我已经尝试了几种方法,但都不是令人满意的。

这是我已经尝试过的:

  1. ExceptionSettings.SetBreakWhenThrownMSDN
    这非常慢(请参阅此连接问题)。我已经尝试了来自问题“ Toggle “Break when an exception is throwed.”中的方法。使用宏或键盘快捷键“并且似乎都不能可靠地工作:在大多数情况下,只有顶级复选框被设置,并且在调试时它实际上不会因异常而中断。

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

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

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

    我尝试过使用IVsDebugger.AdviseDebugEventCallbackMSDN)并传入IDebugEventCallback2MSDN)的实现,但我总是得到nullpEngine也没有IDebugEngineCreateEvent2)。

    我确实得到了IDebugSessionCreateEvent2(未记录的?)并且可以从中得到IDebugSession2,但是它的SetException调用总是给我一个HRESULT错误的论点,所以我可能在这里遗漏了一些东西(SetException从引擎调用IVsLoader给了确定,只是不起作用)。

是否有其他方法比这些方法更好,或者我错过了现有方法中的某些内容?


更新/注意:
如果你发现这个问题是因为你想要一个更快的“打破所有异常”,我做了一个免费的扩展,你可以从 Visual Studio Gallery 获得:Exception Breaker

4

1 回答 1

10

自动化接口是不可能的。为了提高使用它们的性能,我创建了一个从异常组到ExceptionSettings对象以及异常名称到对象的缓存ExceptionSetting。这使我能够绕过ExceptionSettings.Item对调用的单个异常的快速查找SetBreakWhenThrown,但不幸的是,内部实现SetBreakWhenThrown包括验证参数的调用,这反过来又触发了困扰整个方法的内部枚举过程。缓存比不使用宏的代码快大约 4 倍,但我们仍在讨论会使 IDE 挂起几分钟的代码......

注意:到目前为止,以下说明仅在 Visual Studio 2012 中进行了测试。

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

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改用。

于 2013-03-23T23:17:33.900 回答