/// <summary> /// Submits a Dr. Watson (aka Windows Error Reporting / WER) crash report and then terminates the process. /// </summary> /// <param name="uncaughtException">Unhandled exception causing the crash</param> /// <exception cref="System.Runtime.InteropServices.COMException"> /// Some failure HRESULTs map to well-defined exceptions, while others do not map /// to a defined exception. If the HRESULT maps to a defined exception, ThrowExceptionForHR /// creates an instance of the exception and throws it. Otherwise, it creates an instance /// of System.Runtime.InteropServices.COMException, initializes the error code field with /// the HRESULT, and throws that exception. When this method is invoked, it attempts to /// retrieve extra information regarding the error by using the unmanaged GetErrorInfo /// function. /// </exception> private static void SubmitReport(Exception uncaughtException) { lock (s_reportCreationLock) { if (uncaughtException == null) { throw new ArgumentNullException("uncaughtException"); } ReportInformation reportInformation = new ReportInformation(); reportInformation.dwSize = Marshal.SizeOf(reportInformation); reportInformation.hProcess = s_hCurrentProcess; reportInformation.hwndParent = s_hwndMainWindow; reportInformation.wzApplicationName = s_applicationName; reportInformation.wzApplicationPath = s_applicationPath; reportInformation.wzConsentKey = null; // null = the name specified by the pwzEventType parameter of WerReportCreate. reportInformation.wzDescription = null; // we can't provide a description of the problem - this an uncaught = *unexpected* exception reportInformation.wzFriendlyEventName = null; // null = the name specified by pwzEventType parameter of WerReportCreate. ReportHandle reportHandle; HandleHResult(NativeMethods.WerReportCreate( powerShellEventType, ReportType.WerReportCritical, reportInformation, out reportHandle)); using (reportHandle) { SetBucketParameters(reportHandle, uncaughtException); // http://msdn.microsoft.com/en-us/library/bb513622(VS.85).aspx says: // If the server asks for a mini dump and you specify WerDumpTypeHeapDump for the dumpType parameter, // WER will not send the heap dump to the Watson server. However, if the server asks for a heap dump // and the dumpType is WerDumpTypeMiniDump, WER will send the mini dump to the server. // Thus, it is recommended that you set dumpType to WerDumpTypeMiniDump HandleHResult(NativeMethods.WerReportAddDump( reportHandle, s_hCurrentProcess, IntPtr.Zero, // thread id is only required for *micro* dumps DumpType.MiniDump, IntPtr.Zero, // exception details. IntPtr.Zero, // dumpCustomOptions - if this parameter is NULL, the standard minidump information is collected. /*DumpFlags.NoHeap_OnQueue*/0)); // can't use NoHeap_OnQueue, because then we probably won't // be able to request full heap dumps via http://watson web UI SubmitResult submitResult = SubmitResult.ReportFailed; SubmitFlags submitFlags = SubmitFlags.HonorRecovery | SubmitFlags.HonorRestart | SubmitFlags.OutOfProcess | SubmitFlags.AddRegisteredData; if (WindowsErrorReporting.s_unattendedServerMode) { submitFlags |= SubmitFlags.Queue; } HandleHResult(NativeMethods.WerReportSubmit( reportHandle, Consent.NotAsked, submitFlags, out submitResult)); // At this point we have submitted the Watson report and we want to terminate the process // as quickly and painlessly as possible (and possibly without sending additional Watson reports // via the default .NET or OS handler). // Alternatives: native TerminateProcess, managed Environment.Exit, managed Environment.FailFast Environment.Exit((int)submitResult); } } }
private static void SubmitReport(Exception uncaughtException) { lock (reportCreationLock) { ReportInformation information = null; ReportHandle handle; if (uncaughtException == null) { throw new ArgumentNullException("uncaughtException"); } information = new ReportInformation { dwSize = Marshal.SizeOf(information), hProcess = hCurrentProcess, hwndParent = hwndMainWindow, wzApplicationName = applicationName, wzApplicationPath = applicationPath, wzConsentKey = null, wzDescription = null, wzFriendlyEventName = null }; HandleHResult(NativeMethods.WerReportCreate("PowerShell", ReportType.WerReportCritical, information, out handle)); using (handle) { SetBucketParameters(handle, uncaughtException); HandleHResult(NativeMethods.WerReportAddDump(handle, hCurrentProcess, IntPtr.Zero, DumpType.MiniDump, IntPtr.Zero, IntPtr.Zero, 0)); SubmitResult reportFailed = SubmitResult.ReportFailed; SubmitFlags flags = SubmitFlags.HonorRecovery | SubmitFlags.HonorRestart | SubmitFlags.AddRegisteredData | SubmitFlags.OutOfProcess; if (unattendedServerMode) { flags |= SubmitFlags.Queue; } HandleHResult(NativeMethods.WerReportSubmit(handle, Consent.NotAsked, flags, out reportFailed)); Environment.Exit((int) reportFailed); } } }
/// <summary> /// Sends the error report email using the data stored in Session. /// </summary> /// <param name="errorReport">The error report.</param> /// <remarks>Documented by Dev09, 2009-07-16</remarks> private void SendEmail(ErrorReport errorReport) { try { MailMessage mail = new MailMessage(ConfigurationManager.AppSettings["ErrorReportDefaultSender"].ToString(), ConfigurationManager.AppSettings["ErrorReportReceiver"].ToString()); ReportInformation report = new ReportInformation(errorReport.FileName); mail.Subject = string.Format("MemoryLifter Version {0} Error Report", report.MLVersion); // message body containing the user's message and stack trace string separator = ConfigurationManager.AppSettings["EmailSeparator"].ToString(); string reportDate = String.Format("\t\t<p>Report from {0} at {1}</p>\r\n\r\n", report.Date, report.Time); string usermail = String.Format("\t\t<p>User E-Mail:<br />\r\n{0}</p>\r\n\r\n", errorReport.Sender); string message = String.Format("\t\t<p>{0}<br />\r\nUser Message:<br />\r\n{1}<br />\r\n{2}</p>\r\n\r\n", separator, separator, errorReport.Message); string trace = String.Format("\t\t<p>{0}<br />\r\nStack Trace:<br />\r\n{1}<br />\r\n{2}</p>\r\n", separator, separator, errorReport.StackTrace.Replace(Environment.NewLine, "<br />\r\n")); string body = reportDate + usermail + message + trace; mail.Body = "<HTML>\r\n\t<HEAD>\r\n\t\t<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=utf-8'>\r\n\t</HEAD>\r\n\t<BODY>\r\n" + body + "\t</BODY>\r\n</HTML>"; mail.IsBodyHtml = true; mail.BodyEncoding = System.Text.Encoding.UTF8; //include the users mail address as reply-to if (!String.IsNullOrEmpty(errorReport.Sender)) { //OMICRON spam filter kills the mail if the user address is the From-address mail.Headers["Reply-To"] = errorReport.Sender; } // write the attachment to a MemoryStream then attach to email using (MemoryStream ms = new MemoryStream()) { foreach (byte[] dataChunk in errorReport.DataChunks) ms.Write(dataChunk, 0, dataChunk.Length); ms.Position = 0; // CRITICAL mail.Attachments.Add(new Attachment(ms, errorReport.FileName, "application/zip")); // send the email through the omicron smtp server SmtpClient smtp = new SmtpClient(ConfigurationManager.AppSettings["MailServer"].ToString()); smtp.Send(mail); } } catch (Exception e) { Log("SendEmail exception: " + e.ToString()); SmtpFailedRecipientsException smtpexp = e as SmtpFailedRecipientsException; if (smtpexp != null) { foreach (SmtpFailedRecipientException recipient in smtpexp.InnerExceptions) Log("FailedRecipient: " + recipient.FailedRecipient + " StatusCode: " + recipient.StatusCode.ToString()); } throw; } }