C++接入CrashRpt并上报分析崩溃信息

article/2025/10/19 0:05:57

项目需要监测在Windows平台的崩溃情况,折腾了两天终于弄好了,记录一下。

1.捕获崩溃信息

接到这个需求,心想应用崩溃系统会收到信号,应该有相应的函数可以监听,上网搜索,果不其然函数

SetUnhandledExceptionFilter

便有此功能,用法也不复杂,在项目里实现之后发现监测不到【Debug/Release】~~~我勒个擦

搜索 SetUnhandledExceptionFilter无效 貌似蛮多人遇到这个问题的,参考几个博客的内容

尝试了几次依然还是捕获失败,遂放弃了此种方式。

搜索有没有相关的SDK可以使用,还好找到了CrashRpt库,接口简洁接入方便,官方提供的示例

CrashRpt: An Example of Using CrashRpt API

参照示例接入,发现确实可以捕获到崩溃(*^▽^*),而且捕获的信息参数里有崩溃的必要信息

但是来了,但是造了几个崩溃测试了几把,这几个参数一直为空~~我去~~

没办法只能上传崩溃堆栈了,幸好参数里有崩溃信息文件的地址

 读取该文件,哎呀,崩溃时改文件还未写入,尼玛~~~看来要自己写崩溃信息文件了

参考两种Dump(崩溃日志)文件生成的方法及比较博文成功将崩溃信息写入文件,

2.信息上报给服务器

信息上报需要注意,可能由于还未上传程序便结束了,因此主线程最好短暂休眠,给上报线程预留时间

3.分析崩溃信息,定位崩溃原因

使用WinDbg工具【需下载Windows SDK】

打开WinDbg,依次进行下面操作:
File -> Symbol File Path -> 选择pdb文件存放路径。
File -> Image File Path -> 选择exe文件存放路径。
File -> Open Crash Dump -> 选择DMP文件存放路径。
最后会弹出WinDbg对崩溃文件的初步分析的结果,在下面的输入框中输入“!analyze -v”,意思是软件进行对崩溃文件进行分析,并显示出来,然后根据分析结果定位崩溃原因。

Debug->Stop Debugging停止当前分析

至此,Windows平台捕获C++崩溃,上报并分析定位崩溃原因的功能便完成了。

实现代码如下:


#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <stdlib.h>  
#include <windows.h>#include <strsafe.h>
#pragma comment(lib,"DbgHelp.lib")#include "include/CrashRpt.h" void log(const std::string& str)
{std::cout << str.c_str() << std::endl;
}std::string StringWideCharToUtf8(const std::wstring& strWideChar)
{std::string ret;if (!strWideChar.empty()){int nNum = WideCharToMultiByte(CP_UTF8, 0, strWideChar.c_str(), -1, nullptr, 0, nullptr, FALSE);if (nNum){char* utf8String = new char[nNum + 1];utf8String[0] = 0;nNum = WideCharToMultiByte(CP_UTF8, 0, strWideChar.c_str(), -1, utf8String, nNum + 1, nullptr, FALSE);ret = utf8String;delete[] utf8String;}}return ret;
}//将崩溃信息写入文件
typedef BOOL(WINAPI* TKPGetModuleHandleEx)(DWORD dwFlags, LPCTSTR lpModuleName, HMODULE* phModule);
VOID createCrashDump(struct _EXCEPTION_POINTERS* pExceptionPointers, std::string& path)
{//收集信息HMODULE hModule;WCHAR szModuleName[MAX_PATH] = { 0 };TKPGetModuleHandleEx pFun = (TKPGetModuleHandleEx)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetModuleHandleExW");if (!pFun) {return;}pFun(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)pExceptionPointers->ExceptionRecord->ExceptionAddress, &hModule);GetModuleFileName(hModule, szModuleName, ARRAYSIZE(szModuleName));//生成 mini crash dumpBOOL bMiniDumpSuccessful;WCHAR szPath[MAX_PATH];WCHAR szFileName[MAX_PATH];WCHAR* szAppName = L"DumpFile";WCHAR* szVersion = L"v1.0";DWORD dwBufferSize = MAX_PATH;HANDLE hDumpFile;SYSTEMTIME stLocalTime;MINIDUMP_EXCEPTION_INFORMATION ExpParam;GetLocalTime(&stLocalTime);GetTempPath(dwBufferSize, szPath);StringCchPrintf(szFileName, MAX_PATH, L"%s%s", szPath, szAppName);CreateDirectory(szFileName, NULL);StringCchPrintf(szFileName, MAX_PATH, L"%s%s//%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",szPath, szAppName, szVersion,stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,GetCurrentProcessId(), GetCurrentThreadId());hDumpFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);ExpParam.ThreadId = GetCurrentThreadId();ExpParam.ExceptionPointers = pExceptionPointers;ExpParam.ClientPointers = TRUE;MINIDUMP_TYPE MiniDumpWithDataSegs = (MINIDUMP_TYPE)(MiniDumpNormal| MiniDumpWithHandleData| MiniDumpWithUnloadedModules| MiniDumpWithIndirectlyReferencedMemory| MiniDumpScanMemory| MiniDumpWithProcessThreadData| MiniDumpWithThreadInfo);bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);path = StringWideCharToUtf8(szFileName);return;
}//程序崩溃时CrashRpt库抛出的监听事件
int CALLBACK crashCallback(CR_CRASH_CALLBACK_INFO* pInfo)
{// The application has crashed!// Close the log file here// to ensure CrashRpt is able to include it into error reportstd::string filePath;createCrashDump(pInfo->pExceptionInfo->pexcptrs, filePath);unsigned len = 0;FILE* fp = fopen(filePath.c_str(), "rb");if (fp){fseek(fp, 0, SEEK_END);len = ftell(fp);fclose(fp);}//此处将数据上报服务器【子线程上报】//主线程暂时休眠1秒Sleep(1000);log("crash------");return CR_CB_CANCEL;
}int installCrashRpt()
{CR_INSTALL_INFO info;memset(&info, 0, sizeof(CR_INSTALL_INFO));info.cb = sizeof(CR_INSTALL_INFO);info.pszAppName = _T("Test");info.pszAppVersion = _T("1.0.0");info.pszEmailSubject = _T("Test Error Report");//info.uPriorities[CR_HTTP] = 3;  // 首先使用HTTP的方式发送错误报告info.uPriorities[CR_SMTP] = 2;  // 然后使用SMTP的方式发送错误报告  info.uPriorities[CR_SMAPI] = 1; //最后尝试使用SMAPI的方式发送错误报告    // 捕获所有能够捕获的异常, 使用HTTP二进制编码的方式传输info.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS;info.dwFlags |= CR_INST_HTTP_BINARY_ENCODING;info.dwFlags |= CR_INST_APP_RESTART;info.dwFlags |= CR_INST_SEND_QUEUED_REPORTS;info.pszRestartCmdLine = _T("/restart");// 隐私策略URLinfo.pszPrivacyPolicyURL = _T("http://myapp.com/privacypolicy.html");int nResult = crInstall(&info);if (nResult != 0){TCHAR szErrorMsg[512] = _T("");crGetLastErrorMsg(szErrorMsg, 512);_tprintf_s(_T("%s\n"), szErrorMsg);log("crash rpt set falied");return 1;}log("crash rpt set success");crSetCrashCallback(crashCallback, NULL);
}int main(void)
{installCrashRpt();int* p=new int;delete p;*p = 5;system("pause");return 0;
}

附:接入CrashRpt除了头文件需要的文件列表

捕获崩溃需Release模式

参考资料:

应用程序异常处理与崩溃收集

SetUnhandledExceptionFilter拦不住的崩溃

分析两种Dump(崩溃日志)文件生成的方法及比较

vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法


http://chatgpt.dhexx.cn/article/d8RnHrru.shtml

相关文章

计算机中丢失crashrpt,修复crashrpt.dll

crashrpt.dll是电脑系统必备的一个DLL组件修复程序。系统重要文件 crashrpt.dll 。crashrpt.dll(含64位)在电脑中起着重要作用。比如电脑中的部分软件的正常运行就离不开它&#xff0c;如果缺少这款dll&#xff0c;会给用户带来不少麻烦。一旦发现自己的电脑这款crashrpt.dll出…

计算机中丢失crashrpt,crashrpt.dll

crashrpt.dll是smartFTP中一款重要的dll文件&#xff0c;缺少它将导致软件的部分功能无法实现或者无法启动&#xff0c;如果计算机弹出crashrpt.dll丢失或者找不到crashrpt.dll的问题&#xff0c;下载一个crashrpt.dll文件修复一下即可解决问题&#xff0c;需要的朋友可以下载&…

crashrpt

今天原本打算在谷歌上搜索处理SEH的文章&#xff0c;以使我不需要在每一个线程中使用__try{}__except()代码块包裹代码的情况下&#xff0c;就能在任意线程抛出SEH时生成MiniDump文件。不过最后的结果是处理SEH的文章没有搜索出几篇&#xff0c;却幸运的搜索出了满足我需要的工…

Windows平台崩溃转储系统crashrpt的使用

概述 CrashRpt 是一个免费的、轻量级的开源错误报告库开源库&#xff0c;旨在拦截C程序中的异常&#xff0c;收集有关崩溃的技术信息并通过互联网向软件供应商发送错误报告&#xff0c;用于在 Microsoft Visual Studio IDE 中创建并在 Windows 中运行C应用程序。&#xff08;不…

Android APK及签名

APK是AndroidPackage的缩写&#xff0c;即Android安装包(apk)。APK是类似Symbian Sis或Sisx的 文件格式。通过将APK文件直接传到 Android模拟器或Android手机中执行即可安装。apk文件和sis一样&#xff0c;把 android sdk编译的工程打包成一个安装程序文件&#xff0c;格式为ap…

安卓应用签名

安卓应用release模式是需要签名的&#xff0c;否则无法安装&#xff0c;debug模式不需要的 签名可以用keytool生成密钥文件&#xff0c;然后在build.gradle中指定即可。 一、生成密钥文件 keytool -genkey -alias noalias -keypass abcd1234 -keyalg RSA -keysize 2048 -valid…

Android为App签名(为apk签名)

写博客是一种快乐&#xff0c;前提是你有所写&#xff0c;与人分享&#xff0c;是另一种快乐&#xff0c;前提是你有舞台展示&#xff0c;CSDN就是这样的舞台。 这篇文章是android开发人员的必备知识&#xff0c;是我特别为大家整理和总结的&#xff0c;不求完美&#xff0c;但…

AndroidStudio应用签名

1、新建存放签名文件的文件夹 Build 2、初次没有账号 点击Create new 创建 3、签名成功后会在build。gradle 生成下面的数据 4、AS中调出黑窗口写入 keytool -list -v -keystore “L:/boxin/bx.jks” 签名地址 输入密码 5、找到MD5 SHA1 后面的密钥就是你的应用签名

android app签名详解

本文及文中图片转自&#xff1a;https://mp.weixin.qq.com/s?__bizMzIwMzYwMTk1NA&mid2247493825&idx1&sne926da39c6bd51397851d7e330d6ba24&chksm96ce498ca1b9c09a7865264b26eadcf27bd012e9acc999b3eb3ca5c440266642763b6be27416&mpshare1&scene23&a…

Android应用签名之AS签名

废话不多说直接上图 如之前未生成jks文件则&#xff0c;点击create new .. 这里只要输入几个必要项 Key store path&#xff08;生产key文件的保存路径 &#xff09; Key store password&#xff08;key 存储密码&#xff09; Key alias&#xff08;key别名&#xff09; Key p…

安卓应用程序的签名

签名安卓应用程序 Android应用以它的包名作为唯一标识。如果在同一部手机上安装两个包名相同的应用&#xff0c;后面安装的应用就会覆盖前面安装的应用。为了避免这种情况的发生&#xff0c;Android要求对作为产品发布的应用进行签名。 签名主要有如下两个作用&#xff1a; 1.确…

android app签名方法

1、生成签名文件 在android studio 里操作如下&#xff1a; 填完即可。 会产生这个签名文件。 2、签名app 到jdk的bin文件夹下输入下面命令&#xff1a; jarsigner -verbose -keystore D:\appkey\geming.jks D:\svn\Bigdata\IOT\iot-village-app\village\platforms\android\…

Android应用签名

为了要签名&#xff1f; 开发Android的人这么多&#xff0c;完全有可能大家都把类名&#xff0c;包名起成了一个同样的名字&#xff0c;这时候如何区分&#xff1f;签名这时候就是起区分作用的。 由于开发商可能通过使用相同的Package Name来混淆替换已经安装的程序&#xff0c…

Android App签名

Andriod应用程序如果要在手机或模拟器上安装&#xff0c;必须要有签名&#xff01; 1.签名的意义   为了保证每个应用程序开发商合法ID&#xff0c;防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序&#xff0c;我们需要对我们发布的APK文件进行唯一…

Android开发给apk签名

前言 最近360加固助手签名突然收费了&#xff0c;加固完后要自己签名了。在此记录一下自己使用命令行签名步骤。 之后又更新了加固助手&#xff0c;点击自动签名提示如下&#xff1a; 之前没提示工具包手动签名&#xff0c;平时也就加固下应用&#xff0c;也没太注意工具包&…

Andorid进行签名的方式

目录 Android签名的简介 1.Android签名的作用 2.签名的方式 2.1签名方式的比较 3.在AS上操作的一般步骤(手动签名) 3.1 在AS操作步骤如下图 4.apk常用的签名方法(系统签名)有两种 4.1 使用工具对apk进行签名 4.2 在Ubuntu系统下&#xff0c;通过命令行进行签名 Androi…

Android APP的签名

Android APP的签名 Android项目以它的包名作为唯一的标识&#xff0c;如果在同一部手机上安装两个包名相同的APP&#xff0c;后者就会覆盖前面安装的应用。为了避免Android APP被随意覆盖&#xff0c;Android要求对APP进行签名。下面介绍对APP进行签名的步骤 1、选择builder菜…

keil中c语言定义数组,如题,KeilC51位变量能不能定义数组

公告&#xff1a; 为响应国家净网行动&#xff0c;部分内容已经删除&#xff0c;感谢读者理解。 话题&#xff1a;如题,KeilC51位变量能不能定义数组回答&#xff1a;试试呗我的结论是不行 会报错 error C168: array of bit 手册描述&#xff1a;An array may not have type bi…

【C 语言】数组 ( 数组类型表达 | 定义数组类型 )

文章目录 总结一、数组类型表达二、定义数组类型三、代码示例 总结 // 定义类数组数据类型 int [10] , 类型别名为 ArrayTypetypedef int (ArrayType)[10];// 与 int array[10] {0}; 作用相同ArrayType array2 {0};一、数组类型表达 C 语言中的 数据类型 分为 基础数据类型 ,…

JavaScript定义数组

JavaScript定义数组 JavaScript中定义数组的方法&#xff1a; 定义时直接给数组元素赋值 var arr[值1,值2,值3....]定义一个空数组 var arr[];定义一个空数组并通过索引来赋值 var arrnew Array(); arr[0]1; arr[1]2;提示&#xff1a; JavaScript为数组提供了一个length属…