开发的软件在实际客户使用时会出现崩溃闪退情况,很难确定具体原因,log 日志也不方便,但一般操作系统或第三方会提供方法用于获取崩溃软件时的上下文环境信息,包含调用堆栈、局部变量值,形成一个dump日志文件,这些dump文件在开发机上开发工程中打开即可查看当时崩溃环境信息,帮助查看问题,有的软件,就是在崩溃闪退时通过发送dump文件到原开发商,帮助其确定bug。这里我们介绍一种在windows 下获取dump崩溃日志方法: MiniDumpWriteDump()。

  1. 封装 MiniDumpWriteDump 函数形成类文件:
    Debug.h 文件

    #pragma once 
    
    #include <iostream>
    #include <string>
    
    #include <QApplication>
    #include <QString>
    #include <QDir>
    #include <QDateTime>
    
    #if defined(Q_OS_WIN32)   // Q_OS_WIN32
    #include <windows.h>
    #endif
    
    namespace ysm{
    
    	class Debug {
    
    	public:
    #if defined(Q_OS_WIN32) // 		#if defined(_MSC_VER) && _MSC_VER >= 1400
    	// 奔溃回调
    	static LONG WINAPI  crashStackCallback(struct _EXCEPTION_POINTERS* exceptionInfo);
    #endif
    
    	};
    }
    
    

    Debug.cpp 文件

    #include "debug.h"
    
    #include <QApplication>
    #include <QString>
    #include <QDir>
    #include <QDateTime>
    
    #if defined(Q_OS_WIN32)   // Q_OS_WIN32
    #include <Dbghelp.h>
    //#pragma comment(lib, "Dbghelp.lib")
    #endif
    
    namespace ysm {
    
    
    
    #if defined(Q_OS_WIN32)
    
    	LONG WINAPI Debug::crashStackCallback(struct _EXCEPTION_POINTERS* exceptionInfo) {
    		//QCoreApplication::applicationDirPath();
    		//QApplication *app = QCoreApplication::app();
    		QString savePath = QCoreApplication::applicationDirPath() + "/dump/";
    		QDir dir(savePath);
    		if(!dir.exists() && !dir.mkpath(savePath)) {
    			//app->exit(E_UNEXPECTED);
    			return EXCEPTION_EXECUTE_HANDLER;
    		}
    
    		savePath.append("assit_");
    		savePath.append(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
    		savePath.append(".dmp");
    
    		HANDLE dump = CreateFileW(savePath.toStdWString().c_str(), GENERIC_WRITE,
    								  0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    		if(INVALID_HANDLE_VALUE == dump) {
    			//app->exit(E_UNEXPECTED);
    			return EXCEPTION_EXECUTE_HANDLER;
    		}
    
    		MINIDUMP_EXCEPTION_INFORMATION miniDumpExceptionInfo;
    		miniDumpExceptionInfo.ExceptionPointers = exceptionInfo;
    		miniDumpExceptionInfo.ThreadId = GetCurrentThreadId();
    		miniDumpExceptionInfo.ClientPointers = TRUE;
    		DWORD idProcess = GetCurrentProcessId();
    		MiniDumpWriteDump(GetCurrentProcess(), idProcess, dump,
    						  MiniDumpWithFullMemory, &miniDumpExceptionInfo, NULL, NULL);
    
    		// 第四个参数 DumpType 指定类型,用于生成包含不同信息、大小的dump日志。
    		CloseHandle(dump);
    
    		//app->exit(E_UNEXPECTED);
    		return EXCEPTION_EXECUTE_HANDLER;
    	}
    	
    #endif
    
    
    }
    
    
  2. 项目的启动时设置崩溃回调函数:
    MainWindow.cpp

    #include "Debug.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
    #if defined(Q_OS_WIN32)
    	SetUnhandledExceptionFilter(Debug::crashStackCallback);
    #endif
    }
    
  3. 在项目中写个空指针赋值的语句,测试崩溃:

    	// 崩溃日志测试
    	qint32 *i = nullptr;
    	*i = 0;
    
  4. 运行项目, 查看dump崩溃日志:
    在这里插入图片描述

  5. 在开发机上打开dump日志:
    在这里插入图片描述
    在这里插入图片描述

  6. 注意:

   dump文件必须与.pdb文件联合使用,才能定位问题,所以,每个版本的exe,必须保存与之对应的.pdb文件

  那么下一个问题就是QT项目中,怎样让release版本怎样生成pdb文件?
  解决方案:
  在pro配置文件中,添加:

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
  1. 完毕。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐