/// <summary> /// Reports the current non-fatal exception using a process snapshot (if InitializeHandlesForSnapshot has been called) /// </summary> /// <returns>true if the report was successfully taken, false otherwise</returns> private bool ReportException() { bool reportTaken = false; string dbgHelperPath; // If we found the helper exe lets call it if (IsHelperExeFound(out dbgHelperPath)) { using (Process p = new Process()) { // assemble the arguments to the helper, if this returns false we can not proceed string helperArguments; if (PrepareHelperArguments(out helperArguments)) { p.StartInfo = new ProcessStartInfo(dbgHelperPath, helperArguments) { // Prevent the helper process from spawning a new window CreateNoWindow = true, // When UseShellExecute is off, the .NET framework will always call CreateProcess with the bInheritHandles true, which is required to trigger the event UseShellExecute = false, }; p.Start(); if (_eventHandle != IntPtr.Zero) { // wait for the event trigger from the helper or the helper to exit (a maximum of 10 second) // we should keep this timeout low because the IDE will be hung while waiting on this IntPtr[] handles = new IntPtr[] { _eventHandle, p.Handle }; // This should be the landing point for all non-fatal watson dumps, // navigate up the callstack to identify the source of the exception UInt32 result = NativeWin32Stubs.WaitForMultipleObjects((UInt32)handles.Length, handles, false, 10000); // If we get an error result back the wait timed out and the report was not taken in time // or if the wait was triggered by the process exiting reportTaken = result == NativeWin32Stubs.WAIT_OBJECT_0; } else // we don't have an eventHandle to wait on so we should just continue { reportTaken = true; } } } } return(reportTaken); }
protected virtual void Dispose(bool disposing) { _disposed = true; #if !SILVERLIGHT // This pointer is no longer valid outside of the exception filter _exceptionPointersPointer = IntPtr.Zero; if (_eventHandle != IntPtr.Zero) { NativeWin32Stubs.CloseHandle(_eventHandle); _eventHandle = IntPtr.Zero; } if (_processHandleDupe != IntPtr.Zero) { NativeWin32Stubs.CloseHandle(_processHandleDupe); _processHandleDupe = IntPtr.Zero; } if (_threadHandleDupe != IntPtr.Zero) { NativeWin32Stubs.CloseHandle(_threadHandleDupe); _threadHandleDupe = IntPtr.Zero; } #endif }
/// <summary> /// Sets up for taking a snapshot by initializing the necessary handles for the helper process /// </summary> /// <remarks> /// This must be called from an Exception Filter inorder to gather the current exception information. /// </remarks> /// <returns>true on success and false on failure</returns> private unsafe bool InitializeHandlesForSnapshot() { // Grab the pointer to the exception _exceptionPointersPointer = Marshal.GetExceptionPointers(); NativeWin32Stubs.SECURITY_ATTRIBUTES secAttrib = new NativeWin32Stubs.SECURITY_ATTRIBUTES(); secAttrib.bInheritHandle = true; // Prepare id (ThreadId_DateTime) is sufficient to uniquely identify this snapshot request (used by helper process to name the dump file) _snapshotId = string.Format("{0}_{1}", Thread.CurrentThread.ManagedThreadId, unchecked ((ulong)DateTime.Now.ToBinary())); // pointer to the security attributes structure IntPtr pSecAttrib = IntPtr.Zero; // handle to this thread IntPtr hThread = IntPtr.Zero; try { // allocate some native to accommodate the SECURITY_ATTRIBUTES structure needed to create the event object and get its handle pSecAttrib = Marshal.AllocHGlobal(sizeof(NativeWin32Stubs.SECURITY_ATTRIBUTES)); if (pSecAttrib == IntPtr.Zero) { return(false); } // copy the managed structure into native Marshal.StructureToPtr(secAttrib, pSecAttrib, true); // Create event object in the OS (named eventHandleName) and get the handle to it _eventHandle = NativeWin32Stubs.CreateEvent(pSecAttrib, false, false, null); if (_eventHandle == IntPtr.Zero) { return(false); } // Get current thread and process' handle and duplicate them (when you open the handle on a System.Process you must dispose it) using (Process thisProc = Process.GetCurrentProcess()) { // Grab the handle to this thread hThread = NativeWin32Stubs.GetCurrentThread(); if (hThread == IntPtr.Zero) { return(false); } IntPtr hThisProc = thisProc.Handle; // duplicate the thread handle if (!NativeWin32Stubs.DuplicateHandle(hThisProc, hThread, hThisProc, out _threadHandleDupe, 0, true, (uint)NativeWin32Stubs.DESIRED_ACCESS.DUPLICATE_SAME_ACCESS) || _threadHandleDupe == IntPtr.Zero) { return(false); } // duplicate the process handle if (!NativeWin32Stubs.DuplicateHandle(hThisProc, hThisProc, hThisProc, out _processHandleDupe, 0, true, (uint)NativeWin32Stubs.DESIRED_ACCESS.DUPLICATE_SAME_ACCESS) || _processHandleDupe == IntPtr.Zero) { return(false); } } } finally // cleanup the temp handles and native memory we allocated { if (pSecAttrib != IntPtr.Zero) { Marshal.FreeHGlobal(pSecAttrib); } if (hThread != IntPtr.Zero) { NativeWin32Stubs.CloseHandle(hThread); } } return(true); }