我想做一个扩展,以快速切换调试器中的CLR异常 我尝试了几种方法,但都不令人满意。
这是我已经尝试过的:
ExceptionSettings.SetBreakWhenThrown
(MSDN)
这非常慢(见this Connect issue)。我已经尝试了问题“Toggle “Break when an exception is thrown.” using macro or keyboard shortcut”的方法,似乎都没有可靠的工作:在大多数情况下,只有顶级复选框被设置,并且在调试时实际上并没有中断异常。
调用DTE.ExecuteCommand("Debug.Exceptions")
以显示该窗口,并在此之前调用SetWindowsHookEx
(MSDN)在它出现之前拦截它(以便用户没有闪光) )。这似乎是可能的,因为我能够拦截消息并得到HWND
。但它似乎很hacky并且窗口不容易正确操作(它有SysListView32
与自定义复选框和SysTreeView32
的奇怪组合。所以我将其作为最后的机会解决方案。
以某种方式获取托管代码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
为{{{} 1}}(也没有pEngine
)。
我得到IDebugEngineCreateEvent2
(未记录?)并且可以从中获取IDebugSessionCreateEvent2
,但是IDebugSession2
调用总是给我SetException
错误的参数,所以我可能会在这里丢失一些东西(从HRESULT
调用引擎上的SetException
给出了确定,但是没有用。)
是否有其他方法比那些方法更好或者我错过了现有方法?
UPDATE /注:
如果你发现这个问题是因为你想要一个更快的“Break on All Exceptions”,我已经从Visual Studio Gallery获得了免费扩展:Exception Breaker。
答案 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
。