13#include <QApplication>
17#include <QVersionNumber>
27#pragma comment(lib, "dbghelp.lib")
38using FpPostDump = std::function< void(
const QString& dumpPath,
bool success) >;
44LONG applicationCrashHandler(_EXCEPTION_POINTERS* pException);
85 static FpPostDump s_fp_post_dump;
86 static bool s_initialized;
95 return s_fp_prepose_dump;
104 return s_fp_post_dump;
137 qDebug() <<
"Dump capture already initialized";
142 if (
nullptr == fpPre) {
143 fpPre = []() -> QString {
144 QString dumppath = QDir::toNativeSeparators(QApplication::applicationDirPath() +
"/dumps");
146 if (!dir.exists(dumppath)) {
147 if (!dir.mkpath(dumppath)) {
148 qDebug() <<
"Failed to create dump directory:" << dumppath;
150 dumppath = QDir::toNativeSeparators(QDir::tempPath() +
"/app_dumps");
151 dir.mkpath(dumppath);
154 QString filename = QString(
"dump_%1_%2.dmp")
155 .arg(QApplication::applicationName())
156 .arg(QDateTime::currentDateTime().toString(
"yyyyMMdd_hhmmss_zzz"));
157 QString fullPath = QString(
"%1/%2").arg(dumppath).arg(filename);
158 return QDir::toNativeSeparators(fullPath);
162 s_fp_prepose_dump = fpPre;
163 s_fp_post_dump = fpPost;
164 s_initialized =
true;
167 LPTOP_LEVEL_EXCEPTION_FILTER oldFilter = SetUnhandledExceptionFilter(applicationCrashHandler);
169 qDebug() <<
"Previous exception filter was replaced";
172 qDebug() <<
"Dump capture initialized successfully";
183 return s_initialized;
197 QString dumppath = QDir::toNativeSeparators(QApplication::applicationDirPath() +
"/dumps");
199 if (!dir.exists(dumppath)) {
200 dir.mkpath(dumppath);
233 QDateTime cutoffDate = QDateTime::currentDateTime().addDays(-daysToKeep);
234 QFileInfoList files = dir.entryInfoList(QStringList() <<
"*.dmp" <<
"*_info.txt",
235 QDir::Files | QDir::NoDotAndDotDot);
237 int removedCount = 0;
238 for (
const QFileInfo& file : files) {
239 if (file.lastModified() < cutoffDate) {
240 if (QFile::remove(file.absoluteFilePath())) {
241 qDebug() <<
"Removed old dump file:" << file.fileName();
247 if (removedCount > 0) {
248 qDebug() <<
"总共清理了" << removedCount <<
"个旧文件";
257FpPostDump DADumpCapture::s_fp_post_dump =
nullptr;
258bool DADumpCapture::s_initialized =
false;
261LONG applicationCrashHandler(_EXCEPTION_POINTERS* pException)
264 bool dumpSuccess =
false;
265 LPCWSTR lpcwStr = NULL;
270 createPath = fpDump();
273 QString dumppath = QDir::toNativeSeparators(QApplication::applicationDirPath() +
"/dumps");
275 if (!dir.exists(dumppath)) {
276 dir.mkpath(dumppath);
278 createPath = QString(
"%1/dump_%2.dmp").arg(dumppath).arg(QDateTime::currentDateTime().toString(
"yyyyMMdd_hhmmss_zzz"));
281 qDebug() <<
"Application crashed, writing dump file at:" << createPath;
284 QString infoPath = createPath;
285 infoPath.replace(
".dmp",
"_info.txt");
288 FILE* infoFile =
nullptr;
290 fopen_s(&infoFile, infoPath.toLocal8Bit().constData(),
"w");
292 infoFile = fopen(infoPath.toLocal8Bit().constData(),
"w");
297 fprintf(infoFile,
"=== Application Information ===\n");
298 fprintf(infoFile,
"Application: %s\n", QApplication::applicationName().toLocal8Bit().constData());
299 fprintf(infoFile,
"Version: %s\n", QApplication::applicationVersion().toLocal8Bit().constData());
300 fprintf(infoFile,
"Organization: %s\n", QApplication::organizationName().toLocal8Bit().constData());
301 fprintf(infoFile,
"Organization Domain: %s\n", QApplication::organizationDomain().toLocal8Bit().constData());
304 fprintf(infoFile,
"\n=== Crash Information ===\n");
307 QDateTime::currentDateTime().toString(
"yyyy-MM-dd hh:mm:ss.zzz").toLocal8Bit().constData());
308 fprintf(infoFile,
"Process ID: %lu\n", GetCurrentProcessId());
309 fprintf(infoFile,
"Thread ID: %lu\n", GetCurrentThreadId());
310 fprintf(infoFile,
"Exception Code: 0x%08lX\n", pException->ExceptionRecord->ExceptionCode);
311 fprintf(infoFile,
"Exception Address: 0x%p\n", pException->ExceptionRecord->ExceptionAddress);
314 fprintf(infoFile,
"\n=== System Information ===\n");
315 fprintf(infoFile,
"Build ABI: %s\n", QSysInfo::buildAbi().toLocal8Bit().constData());
316 fprintf(infoFile,
"Build CPU Architecture: %s\n", QSysInfo::buildCpuArchitecture().toLocal8Bit().constData());
317 fprintf(infoFile,
"Current CPU Architecture: %s\n", QSysInfo::currentCpuArchitecture().toLocal8Bit().constData());
318 fprintf(infoFile,
"Kernel Type: %s\n", QSysInfo::kernelType().toLocal8Bit().constData());
319 fprintf(infoFile,
"Kernel Version: %s\n", QSysInfo::kernelVersion().toLocal8Bit().constData());
320 fprintf(infoFile,
"Machine Host Name: %s\n", QSysInfo::machineHostName().toLocal8Bit().constData());
321 fprintf(infoFile,
"Pretty Product Name: %s\n", QSysInfo::prettyProductName().toLocal8Bit().constData());
322 fprintf(infoFile,
"Product Type: %s\n", QSysInfo::productType().toLocal8Bit().constData());
323 fprintf(infoFile,
"Product Version: %s\n", QSysInfo::productVersion().toLocal8Bit().constData());
328 std::wstring wlpstr = createPath.toStdWString();
329 lpcwStr = wlpstr.c_str();
330 HANDLE hDumpFile = CreateFileW(lpcwStr, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
332 if (hDumpFile != INVALID_HANDLE_VALUE) {
334 MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
335 dumpInfo.ExceptionPointers = pException;
336 dumpInfo.ThreadId = GetCurrentThreadId();
337 dumpInfo.ClientPointers = TRUE;
340 MINIDUMP_TYPE dumpType =
static_cast< MINIDUMP_TYPE
>(MiniDumpNormal | MiniDumpWithDataSegs
341 | MiniDumpWithHandleData | MiniDumpWithUnloadedModules
342 | MiniDumpWithProcessThreadData);
345 BOOL result = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, dumpType, &dumpInfo, NULL, NULL);
348 qDebug() <<
"Dump file created successfully:" << createPath;
351 DWORD error = GetLastError();
352 qDebug() <<
"Failed to create dump file, error code:" << error;
355 CloseHandle(hDumpFile);
357 DWORD error = GetLastError();
358 qDebug() <<
"Failed to create dump file handle, error code:" << error;
363 fpPostDump(createPath, dumpSuccess);
365 }
catch (
const std::exception& e) {
366 qDebug() <<
"Exception in create dump:" << e.what();
369 return EXCEPTION_EXECUTE_HANDLER;
Dump文件捕获类
Definition DADumpCapture.h:82
static bool isInitialized()
检查是否已初始化
Definition DADumpCapture.h:181
static FpPreposeDump getPreposeDumpFunc()
获取前置处理函数指针
Definition DADumpCapture.h:93
static FpPostDump getPostDumpFunc()
获取后置处理函数指针
Definition DADumpCapture.h:102
static QString getDefaultDumpDirectory()
获取默认dump目录
Definition DADumpCapture.h:195
static void cleanupOldDumps(int daysToKeep=7, const QString &directory=QString())
清理旧的dump文件
Definition DADumpCapture.h:224
static void initDump(FpPreposeDump fpPre=nullptr, FpPostDump fpPost=nullptr)
初始化dump捕获
Definition DADumpCapture.h:132
序列化类都是带异常的,使用中需要处理异常
Definition AppMainWindow.cpp:44
std::function< QString() > FpPreposeDump
函数指针,这个函数指针会在形成dump文件之前执行,要求返回形成dump文件的完整路径,如果没有会赋予一个默认的
Definition DADumpCapture.h:37