19

デバッガーで CLR 例外の中断をすばやく切り替える拡張機能を作成したいと考えています。
私はいくつかのアプローチを試みましたが、どちらも満足のいくものではありませんでした。

これが私がすでに試したことです:

  1. ExceptionSettings.SetBreakWhenThrown( MSDN )
    これは非常に遅いです (この Connect issueを参照してください)。質問からのアプローチを試みました」トグル「例外がスローされたときにブレークします。」ほとんどの場合、トップレベルのチェックボックスのみが設定され、デバッグ時に例外で実際に中断することはありません。

  2. DTE.ExecuteCommand("Debug.Exceptions")ウィンドウを表示するために呼び出し、その直前にSetWindowsHookEx( MSDN ) を呼び出して、表示される前にインターセプトします (ユーザーにフラッシュがないように)。メッセージを傍受して取得できたので、これは可能だと思われますHWND。しかし、ハックしているようで、ウィンドウを適切に操作するのはそれほど簡単ではありません (SysListView32カスタム チェックボックスとの奇妙な組み合わせがありますSysTreeView32)。だから私はそれを最後のチャンスの解決策として残しています。

  3. どういうわけか、マネージ コードの取得IDebugEngine2( MSDN )と、デバッグ セッションの開始時に呼び出しIDebugEngine2.SetException( MSDN ) を行います。これは可能だと思われますが、デバッグ エンジンの取得に問題があります。MSDN フォーラムIVsLoaderで説明されている方法を試してみましたが、デバッグ セッションとは無関係の新しいインスタンスが得られると確信しています。

    ここでも質問をしました:「Visual Studio:VSパッケージからIDebugEngine2を取得する方法(IVsLoaderを除く)」ですが、解決策が得られませんでした。

    IVsDebugger.AdviseDebugEventCallbackMSDNIDebugEventCallback2 )を使用して(MSDN)の実装を渡そうとしましたが、常に取得nullしていますpEngine(どちらも取得していませんIDebugEngineCreateEvent2)。

    私はIDebugSessionCreateEvent2(文書化されていませんか?)それから取得できますIDebugSession2が、その呼び出しは常に間違った引数をSetException与えるため、ここで何かが欠けている可能性があります(エンジンからの呼び出しはOKを返しますが、うまくいきません)。HRESULTSetExceptionIVsLoader

それらよりも優れた他のアプローチはありますか、それとも既存のもので何かを見逃していますか?


更新/注:
「すべての例外でブレーク」を高速化するためにこの質問を見つけた場合は、Visual Studio ギャラリーから入手できる無料の拡張機能を作成しました: Exception Breaker

4

1 に答える 1

10

自動化インターフェースは問題外です。それらを使用してパフォーマンスを向上させるために、例外グループからExceptionSettingsオブジェクトへ、および例外名からオブジェクトへのキャッシュを作成しましたExceptionSettingExceptionSettings.Itemこれにより、呼び出しの個々の例外の迅速なルックアップをバイパスできましたSetBreakWhenThrownが、残念ながら、の内部実装にSetBreakWhenThrownは、引数を検証するための呼び出しが含まれています。これにより、このアプローチ全体を悩ます内部列挙プロセスがトリガーされます。キャッシュはマクロを使用しないコードよりも約4倍高速ですが、IDEを数分間ハングさせるコードについてはまだ話し合っています...

注:以下の手順は、これまでVisualStudio2012でのみテストされています。

SetBreakWhenThrown逆アセンブリビューでステップスルーすると、(検証後の)重要な内部呼び出しがであることがわかりましたsdm::CDebugManager::SetException。シェルデバッガー(SVsShellDebuggerキャスト先のサービス)は、現在のへのアクセスを提供するIVsDebugger実装をしていることがわかります。ソリューションを開いた後、デバッグを開始する前は、このプロパティはnullではありませんでした。IDebuggerInternalIDebugSession3

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 に答える