public int Event(IDebugEngine2 pEngine, IDebugProcess2 pProcess, IDebugProgram2 pProgram, IDebugThread2 pThread, IDebugEvent2 pEvent, ref Guid riidEvent, uint dwAttrib) { try { string threadName = null; if (pThread != null && pEvent != null) { uint attributes; pEvent.GetAttributes(out attributes); if ((uint)enum_EVENTATTRIBUTES.EVENT_SYNC_STOP == attributes) { //HandleException.PrintFrames(pThread); } pThread.GetName(out threadName); //ExtractFrameContent(pThread); //IEnumDebugFrameInfo2 ppEnum = null; } Trace.WriteLine(string.Format("Event {0} Thread {1}", riidEvent, threadName)); if (typeof(IDebugInterceptExceptionCompleteEvent2).GUID == riidEvent) { var interactionEvent = pEvent as IDebugInterceptExceptionCompleteEvent2; ulong cookie; interactionEvent.GetInterceptCookie(out cookie); // another way to get code path: //pProgram.EnumCodePaths( var exceptionInfo = HandleException.PrintFrames(pThread); if (exceptionInfo != null) { if (exceptionInfo.ExceptionKind == null) { exceptionInfo.ExceptionKind = LastExceptionType; } if (exceptionInfo.ExceptionMessage == null) { exceptionInfo.ExceptionMessage = LastExceptionMessage; } SaveToDb(exceptionInfo); } } //HandleException.ProcessEvent(riidEvent, pThread); if (typeof(IDebugProgramCreateEvent2).GUID == riidEvent) { // Add handle } //if (typeof(IDebugBreakEvent2).GUID == riidEvent) if (typeof(IDebugBreakpointEvent2).GUID == riidEvent) { // Might be interesting to get the statement line number here and emit. //var ev = pEvent as IDebugBreakEvent2; var ev = pEvent as IDebugBreakpointEvent2; var info = HandleException.ProcessEvent(riidEvent, pThread); if (info != null) { SaveToDb(info); } } if (riidEvent == typeof(IDebugEntryPointEvent2).GUID) { // This is when execution is just about to the start. // I can't get the reference to the engine, pEngine is always null, and // there doesn't seem to be an interface to fetch it (there is a query interface in docs, but not in dll!) //string engineStr; Guid engineGuid; //pProgram.GetEngineInfo(out engineStr, out engineGuid); //var superEngine = pEngine as IDebugEngine3; //if (superEngine != null) //{ // superEngine.SetAllExceptions(enum_EXCEPTION_STATE.EXCEPTION_STOP_FIRST_CHANCE); //} } else if (riidEvent == typeof(IDebugMessageEvent2).GUID) { var ev = pEvent as IDebugMessageEvent2; var str = ""; uint type; string helpFile; uint helpId; var suc = ev.GetMessage(new enum_MESSAGETYPE[] { enum_MESSAGETYPE.MT_REASON_EXCEPTION }, out str, out type, out helpFile, out helpId); //uint messageType; //var suc = ev.GetMessage( out messageType, out str, out type, out helpFile, out helpId); if (suc == VSConstants.S_OK) { if (str.StartsWith("A first chance exception of type")) { if (pThread != null) { //ExtractFrameContent(pThread); //HandleException.PrintFrames(pThread); LastExceptionMessage = str; LastExceptionType = str; } // First chance exception thrown...but can't figure out how to get stack trace :( } } } // This interface is sent by the debug engine (DE) to the session debug manager (SDM) when a thread is created in a program being debugged. //if (riidEvent == Guid.Parse("{2090ccfc-70c5-491d-a5e8-bad2dd9ee3ea}")) { if (pThread != null) { // ExtractFrameContent(pThread); } } // Process of exception handling. // http://msdn.microsoft.com/es-es/library/bb146610.aspx if (riidEvent == typeof(IDebugExceptionEvent2).GUID || riidEvent == Guid.Parse("{51A94113-8788-4A54-AE15-08B74FF922D0}") ) { IDebugExceptionEvent2 ev = pEvent as IDebugExceptionEvent2; if (ev != null) { var info = new EXCEPTION_INFO[1]; ev.GetException(info); var name = info[0].bstrExceptionName; var state = info[0].dwState; //state == enum_EXCEPTION_STATE.EXCEPTION_STOP_SECOND_CHANCE //ExtractFrameContent(pThread); } } } catch (Exception ex) { Trace.WriteLine(ex.Message); } if (pEngine != null) { Marshal.ReleaseComObject(pEngine); } if (pProcess != null) { Marshal.ReleaseComObject(pProcess); } if (pProgram != null) { Marshal.ReleaseComObject(pProgram); } if (pThread != null) { Marshal.ReleaseComObject(pThread); } if (pEvent != null) { Marshal.ReleaseComObject(pEvent); } return(VSConstants.S_OK); }