【问题标题】:How to set "Break on All Exceptions", from a Package如何从包中设置“中断所有异常”
【发布时间】:2013-03-13 00:59:21
【问题描述】:

我想制作一个扩展来快速切换调试器中的 CLR 异常中断。
我尝试了几种方法,都没有令人满意。

这是我已经尝试过的:

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

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

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

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

    我尝试使用IVsDebugger.AdviseDebugEventCallback (MSDN) 并传入IDebugEventCallback2 (MSDN) 的实现,但我总是得到null 用于pEngine(也没有IDebugEngineCreateEvent2)。

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

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


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

【问题讨论】:

  • 您在这个问题上付出的努力不仅值得 +1,因此我在过去 3 小时内投入了潜在的解决方案。 :) 我相信它现在可能只适用于 VS2012,但希望我们也能在 2010 年实现它。
  • 非常感谢您的帮助!我的技能目前在低级调试方面达到了极限,所以我被困在那里。我希望这个扩展能够为人们节省比我们花在研究上更多的时间。

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


【解决方案1】:

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

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

在反汇编视图中逐步查看SetBreakWhenThrown 发现关键的内部调用(验证后)是sdm::CDebugManager::SetException。事实证明,shell 调试器(您转换为 IVsDebuggerSVsShellDebugger 服务)实现了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

【讨论】:

  • 这太棒了,非常感谢!我实际上发现AdviseDebugEventCallback + IDebugSessionCreateEvent2 也可以工作,只要我使用你的标志组合而不是enum_EXCEPTION_STATE.EXCEPTION_STOP_ALL。最好的部分是异常对话框也注意到了这种变化,所以我不必在第一个版本中替换它。
  • 发现了一个问题。当我调用SetException 时,这会影响Debug->Exceptions 的内容并且通常可以工作,但在当前会话期间不会。例如,如果我打开一个控制台应用程序,会立即为*.vshost.exe 创建会话(我们称之为 Session1)——然后当我按下Run 时,会使用相同的会话,然后在Stop 上重新创建它(会话2)。因此,虽然Debug->Exceptions 显示我的设置,但 Session1 并没有中断它 - 但 Session2 甚至没有再次设置它。
  • 所以SetException 似乎会影响会话之间持续存在的一些内部选项,但当前会话不会立即重新加载此选项。我假设Debug->Exceptions 调用了某种重新初始化/更新方法,但我在 API 中找不到任何合适的东西。
  • EPIC WIN:在非托管调试上浪费了几个小时(以前从未这样做过),发现我必须事先用Guid.Empty(!)调用session.RemoveAllSetExceptions
  • 另一个问题:我在最新版本的扩展中切换到使用IDebuggerInternal,但在我的VS2012(Premium)中找不到Microsoft.VisualStudio.Debugger.Interop.Internal, Version=11.0.0.0。我在VS2010中找到的,但是界面不同:我设法解决了这个问题,但我仍然很好奇VS2012的那个文件在哪里。
猜你喜欢
  • 2013-09-28
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-23
相关资源
最近更新 更多