// To compile link with Dbghelp.lib
// The callstack in release is the same as usual, which means it isn't all that accurate.
#include <stdio.h>
#include <windows.h>
#include <DbgHelp.h>
#include <stdlib.h>
#include <time.h>
#include "SendFileTo.h"
#include "CrashReporter.h"
#include "EmailSender.h"
#include "FileList.h"
#include "FileOperations.h"
CrashReportControls CrashReporter::controls;
// More info at:
// http://www.codeproject.com/debug/postmortemdebug_standalone1.asp
// http://www.codeproject.com/debug/XCrashReportPt3.asp
// http://www.codeproject.com/debug/XCrashReportPt1.asp
// http://www.microsoft.com/msj/0898/bugslayer0898.aspx
LONG ProcessException(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
char appDescriptor[_MAX_PATH];
if ((CrashReporter::controls.actionToTake & AOC_SILENT_MODE) == 0)
{
sprintf(appDescriptor, "%s has crashed.\nGenerate a report?", CrashReporter::controls.appName);
if (::MessageBox( NULL, appDescriptor, "Crash Reporter", MB_YESNO )==IDNO)
{
return EXCEPTION_CONTINUE_SEARCH;
}
}
char dumpFilepath[_MAX_PATH];
char dumpFilename[_MAX_PATH];
sprintf(appDescriptor, "%s %s - %s %s", CrashReporter::controls.appName, CrashReporter::controls.appVersion, __DATE__, __TIME__);
if ((CrashReporter::controls.actionToTake & AOC_EMAIL_WITH_ATTACHMENT) ||
(CrashReporter::controls.actionToTake & AOC_WRITE_TO_DISK)
)
{
if (CrashReporter::controls.actionToTake & AOC_WRITE_TO_DISK)
{
strcpy(dumpFilepath, CrashReporter::controls.pathToMinidump);
WriteFileWithDirectories(dumpFilepath,0,0);
AddSlash(dumpFilepath);
}
else
{
// Write to a temporary directory if the user doesn't want the dump on the harddrive.
if (!GetTempPath( _MAX_PATH, dumpFilepath ))
dumpFilepath[0]=0;
}
unsigned i, dumpFilenameLen;
strcpy(dumpFilename, appDescriptor);
dumpFilenameLen=(unsigned) strlen(appDescriptor);
for (i=0; i < dumpFilenameLen; i++)
if (dumpFilename[i]==':')
dumpFilename[i]='.'; // Can't have : in a filename
strcat(dumpFilepath, dumpFilename);
strcat(dumpFilepath, ".dmp");
HANDLE hFile = CreateFile(dumpFilepath,GENERIC_WRITE, FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile==INVALID_HANDLE_VALUE)
return EXCEPTION_CONTINUE_SEARCH;
MINIDUMP_EXCEPTION_INFORMATION eInfo;
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ExceptionPointers = ExceptionInfo;
eInfo.ClientPointers = FALSE;
if (MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
(MINIDUMP_TYPE)CrashReporter::controls.minidumpType,
ExceptionInfo ? &eInfo : NULL,
NULL,
NULL)==false)
return EXCEPTION_CONTINUE_SEARCH;
CloseHandle(hFile);
}
char silentModeEmailBody[1024];
char subject[1204];
if (CrashReporter::controls.actionToTake & AOC_EMAIL_NO_ATTACHMENT)
{
strcpy(subject, CrashReporter::controls.emailSubjectPrefix);
strcat(subject, appDescriptor);
if (CrashReporter::controls.actionToTake & AOC_SILENT_MODE)
{
sprintf(silentModeEmailBody, "%s version %s has crashed.\r\nIt was compiled on %s %s.\r\n", CrashReporter::controls.appName,CrashReporter::controls.appVersion, __DATE__, __TIME__);
if (CrashReporter::controls.actionToTake & AOC_WRITE_TO_DISK)
sprintf(silentModeEmailBody+strlen(silentModeEmailBody), "Minidump written to %s \r\n", dumpFilepath);
// Silently send email with attachment
EmailSender emailSender;
emailSender.Send(CrashReporter::controls.SMTPServer,
25,
CrashReporter::controls.SMTPAccountName,
CrashReporter::controls.emailRecipient,
CrashReporter::controls.emailSender,
CrashReporter::controls.emailRecipient,
subject,
silentModeEmailBody,
0,
false);
}
else
{
CSendFileTo sendFile;
sendFile.SendMail(0, 0, 0, subject, CrashReporter::controls.emailBody, CrashReporter::controls.emailRecipient);
}
}
else if (CrashReporter::controls.actionToTake & AOC_EMAIL_WITH_ATTACHMENT)
{
strcpy(subject, CrashReporter::controls.emailSubjectPrefix);
strcat(subject, dumpFilename);
strcat(dumpFilename, ".dmp");
if (CrashReporter::controls.actionToTake & AOC_SILENT_MODE)
{
sprintf(silentModeEmailBody, "%s version %s has crashed.\r\nIt was compiled on %s %s.\r\n", CrashReporter::controls.appName,CrashReporter::controls.appVersion, __DATE__, __TIME__);
if (CrashReporter::controls.actionToTake & AOC_WRITE_TO_DISK)
sprintf(silentModeEmailBody+strlen(silentModeEmailBody), "Minidump written to %s \r\n", dumpFilepath);
// Silently send email with attachment
EmailSender emailSender;
FileList files;
files.AddFile(dumpFilepath,dumpFilename,0);
emailSender.Send(CrashReporter::controls.SMTPServer,
25,
CrashReporter::controls.SMTPAccountName,
CrashReporter::controls.emailRecipient,
CrashReporter::controls.emailSender,
CrashReporter::controls.emailRecipient,
subject,
silentModeEmailBody,
&files,
false);
}
else
{
CSendFileTo sendFile;
sendFile.SendMail(0, dumpFilepath, dumpFilename, subject, CrashReporter::controls.emailBody, CrashReporter::controls.emailRecipient);
}
}
return EXCEPTION_EXECUTE_HANDLER;
}
LONG WINAPI CrashExceptionFilter( struct _EXCEPTION_POINTERS *ExceptionInfo )
{
return ProcessException(ExceptionInfo);
}
void DumpMiniDump(PEXCEPTION_POINTERS excpInfo)
{
if (excpInfo == NULL)
{
// Generate exception to get proper context in dump
__try
{
RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
}
__except(DumpMiniDump(GetExceptionInformation()),EXCEPTION_EXECUTE_HANDLER)
{
}
}
else
{
ProcessException(excpInfo);
}
}
void CrashReporter::Start(CrashReportControls *input)
{
memcpy(&controls, input, sizeof(CrashReportControls));
#ifndef _DEBUG_CRASH_REPORTER
SetUnhandledExceptionFilter(CrashExceptionFilter);
#endif
}
syntax highlighted by Code2HTML, v. 0.9.1