diff --git a/DFTFringe.pro b/DFTFringe.pro index cf7ec6e0..2b760168 100644 --- a/DFTFringe.pro +++ b/DFTFringe.pro @@ -55,6 +55,7 @@ win32 { LIBS += -L..\build_openCV\install\x64\mingw\bin -llibopencv_highgui460 LIBS += -L..\build_openCV\install\x64\mingw\bin -llibopencv_imgcodecs460 LIBS += -L..\build_openCV\install\x64\mingw\bin -llibopencv_imgproc460 + LIBS += -ldbghelp # for SetUnhandledExceptionFilter # This is for armadillo to not use wrapper. See https://gitlab.com/conradsnicta/armadillo-code#6-linux-and-macos-compiling-and-linking diff --git a/DFTFringe_Dale.pro b/DFTFringe_Dale.pro index c4307ac2..a35afefb 100644 --- a/DFTFringe_Dale.pro +++ b/DFTFringe_Dale.pro @@ -393,6 +393,8 @@ LIBS += D:\opencv\opencv-3.4.12\build\bin\libopencv_calib3d3412.dll #LIBS += D:\armadillo\bin\libarmadillo.dll LIBS += D:\lapack\build64\bin\liblapack.dll LIBS += D:\lapack\build64\bin\libblas.dll + +LIBS += -ldbghelp # for SetUnhandledExceptionFilter } diff --git a/main.cpp b/main.cpp index 64364207..f6d87154 100644 --- a/main.cpp +++ b/main.cpp @@ -26,10 +26,65 @@ #include "spdlog/sinks/stdout_color_sinks.h" #include "boost/stacktrace.hpp" +#ifdef _WIN32 + #include + #include + #include + + LONG WINAPI MyUnhandledExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo) + { + // Create a timestamped filename + time_t now = time(nullptr); + char filename[MAX_PATH]; + strftime(filename, sizeof(filename), "DFTFringeLogs\\crashdump_%Y%m%d_%H%M%S.dmp", localtime(&now)); + + HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + return EXCEPTION_EXECUTE_HANDLER; + } + + if(ExceptionInfo != nullptr) + { + MINIDUMP_EXCEPTION_INFORMATION dumpInfo; + dumpInfo.ThreadId = GetCurrentThreadId(); + dumpInfo.ExceptionPointers = ExceptionInfo; + dumpInfo.ClientPointers = FALSE; + + MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + MiniDumpNormal, + &dumpInfo, + nullptr, + nullptr + ); + } + else + { + MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + MiniDumpNormal, + nullptr, // No exception information + nullptr, + nullptr + ); + } + + CloseHandle(hFile); + + return EXCEPTION_EXECUTE_HANDLER; + } +#endif static void my_terminate_handler() { try { spdlog::get("logger")->critical("Unexpected issue. Stacktrace:\n" + boost::stacktrace::to_string((boost::stacktrace::stacktrace()))); +#ifdef _WIN32 + MyUnhandledExceptionFilter(nullptr); // Call the unhandled exception filter to create a crash dump +#endif } catch (...) {} std::abort(); } @@ -121,6 +176,11 @@ int main(int argc, char *argv[]) // from here, any problematic application exit (for example uncatched exceptions) should call my_terminate_handler std::set_terminate(&my_terminate_handler); +#ifdef _WIN32 + // in case of specific Windows exceptions, we want to catch them and write a minidump + SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); +#endif + #ifndef DALE_DO_NOT_LOG // override QT message handler because qFatal() and qCritical() would exit cleanly without crashlog qInstallMessageHandler(myQtMessageOutput); // replace with nullptr if you want to use original bahavior for debug purpose