18

我想擴展以快速切換調試器中的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),但我總是得到nullpEngine(沒有IDebugEngineCreateEvent2其一)。

    我得到IDebugSessionCreateEvent2(無證?),可以從它那裏得到IDebugSession2,但其SetException電話總是讓我對錯誤的參數的HRESULT,所以我可能會失去了一些東西(從IVsLoader調用引擎SetException給人OK,只是不起作用)。

有沒有其他的方法比那些更好或者我錯過了現有的東西?


UPDATE /注:
如果您發現了這個問題,因爲你想更快「的所有異常中斷」,我做了一個免費的擴展,你可以從Visual Studio庫得到:Exception Breaker

+2

因爲你對這個問題所付出的努力,你值得的不僅僅是+1,所以我在過去的3個小時裏研究了一個潛在的解決方案。 :)我相信它現在可能只適用於VS2012,但希望我們也能在2010年進行。 – 2013-03-23 23:23:12

+0

我真的很感謝你的幫助!我的技能目前在低級調試中達到極限,所以我被困在那裏。我希望這個擴展可以爲人們節省比我們花費的時間更多的時間。 – 2013-03-24 00:58:52

回答

9

自動化接口是出問題。爲了提高使用它們的性能,我創建了一個緩存,從異常組到ExceptionSettings對象和異常名稱到ExceptionSetting對象。這讓我繞過ExceptionSettings.Item來快速查找調用SetBreakWhenThrown的個別異常,但不幸的是,SetBreakWhenThrown的內部實現包含一個調用來驗證參數,這反過來觸發了一個內部枚舉過程,這個過程困擾着整個方法。緩存大約比不使用宏的代碼快4倍,但是我們仍然在討論將代碼掛起幾分鐘的代碼...

注意:以下說明僅在Visual中測試過Studio 2012.

在反彙編視圖中跳過SetBreakWhenThrown,發現關鍵內部調用(驗證後)爲sdm::CDebugManager::SetException。事實證明,shell調試器(SVsShellDebugger服務,您投到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代替。

+0

這太神奇了,非常感謝!我實際上發現'AdviseDebugEventCallback' +'IDebugSessionCreateEvent2'工作得很好,只要我使用你的標誌組合而不是'enum_EXCEPTION_STATE.EXCEPTION_STOP_ALL'。最好的部分是Exception對話框也會注意到這個改變,所以我不必在第一個版本中替換它。 – 2013-03-24 00:52:50

+0

發現問題。當我調用'SetException'時,這會影響'Debug-> Exceptions'的內容,並且通常會起作用,但不會影響當前會話期間的內容。例如,如果我打開一個控制檯應用程序,會話(我們稱之爲Session1)立即爲'* .vshost.exe'創建 - 然後當我按下'Run'時,使用同一個會話,然後重新創建它'停止'(Session2)。所以當'Debug-> Exceptions'顯示我的設置時,Session1不會中斷 - 但Session2甚至不需要再次設置它。 – 2013-03-26 10:47:12

+0

所以'SetException'似乎會影響會話之間持續存在的某些內部選項,但當前會話不會立即重新加載此選項。我假設'Debug-> Exceptions'調用某種重新初始化/更新方法,但我找不到任何合適的API。 – 2013-03-26 10:48:36

相關問題