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

article/2025/10/19 0:04:19

概述

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

官网为:CrashRpt - A crash reporting system for Windows applications (sourceforge.net)

官网介绍它支持 Visual C++ 2005、2008、2010、2012 和 Visual C++ Express ,笔者使用的编译器Visual Studio 2022也支持。 可以针对 32 位和 64 位平台进行编译。截止2022年10月,适用于 Windows XP以上的操作系统。

1、它可以处理主线程和用户模式程序的所有工作线程中的异常:SEH 异常(Structured Exception Handling 结构化异常处理)、未处理C++类型异常、信号和 CRT (C运行时)错误。在 CrashRpt 可以处理的错误类型中,有:NULL 指针分配、访问冲突、无限递归、堆栈溢出、内存耗尽等。

2、它能生成错误报告,包括小型崩溃转储minidump文件、可扩展的崩溃描述 XML文件、应用程序自定义的文件(如程序日志文件)、桌面屏幕截图和屏幕捕获视频。

3、它提供允许用户查看崩溃报告的 UI以及支持隐私政策定义。

4、它可以使用不同的语言显示其UI,这使得它更适合多语言应用程序。

5、 它在用户同意后在后台发送错误报告。

6、可以通过HTTP(或 HTTPS)、SMTP 和Simple MAPI 的方式从用户端上传崩溃分析文件。

7、崩溃时自动重新启动应用程序(如果用户同意)。

8、使用命令行工具在开发人员端自动处理错误报告。当您从软件用户那里收到大量错误报告时,此选项将非常有用。

9、提供用于API函数接口访问错误报告 。

10、CrashRpt库是轻量级的,这意味着你应该只分发大约1.9 Mb的附加文件与你的软件(dbghelp.dll,CrashRpt.dll,CrashSender.exe)。

体系结构概述

CrashRpt 包含两种功能:错误报告功能错误报告分析功能

1、错误报告功能随客户端软件一起分发,负责处理客户端软件中的异常并将错误报告传递给开发人员。

2、错误报告分析功能旨在帮助开发人员提取错误报告中包含的数据并简化错误报告分析。它通常位于开发人员的一侧,不与客户端软件一起发布。

错误报告功能

错误报告功能由两个核心模块组成:CrashRpt.dll和CrashSender.exe。

CrashRpt.dll 包含用于处理客户端软件中的异常的功能。

CrashSender.exe包含向软件支持团队发送错误报告的功能。

注意:CrashRpt有多个版本,这里的写法是简写,真正编译出来的dll和exe名称类似于(CrashRpt1400.dllCrashSender1400.exe

通常,可执行文件在进程启动时将 CrashRpt.dll 加载到其地址空间中。CrashRpt 的这个实例在加载到进程地址空间的所有 DLL 模块之间共享。客户端应用程序使用 CrashRpt 函数在进程中设置异常处理程序一次,通常在其 main()(或 WinMain()) 函数中。在多线程程序中,客户端在每个工作线程的线程过程的开头额外设置异常处理程序。

错误报告分析功能

错误报告功能也由两个核心模块组成:CrashRptProbe.dll和crprober.exe。

CrashRptProbe.dll实现了可用于访问错误报告数据的API。

crprober.exe 是一个控制台工具,有助于提取错误报告数据并以人类可读的形式编写摘要。

当您从软件用户那里收到许多错误报告时,您将不得不花费大量时间来打开每个报告,分析其内容并编写有关报告的一些摘要。可能有许多报告与同一问题相关,因此打开此类报告不会提供任何新内容,错误报告分析功能旨在解决这些问题。

功能介绍

“错误报告”对话框

当客户端应用程序中发生崩溃时,将显示“错误报告”对话框(请参见下图)。

 “错误报告详细信息”对话框

上面界面的此报告包含哪些内容?链接打开“错误报告详细信息”对话框。

错误报告包含什么?

错误报告是旨在帮助开发人员诊断崩溃原因的文件集合:崩溃小型转储文件、崩溃描述 XML 文件和其他可选文件。

故障小型转储文件 (crashdump.dmp) 包含每个执行线程的操作系统版本、处理器类型、CPU 寄存器状态、局部变量和调用堆栈。

可以在开发人员端使用小型转储文件来确定崩溃的原因并尝试解决问题。(用Windbg工具再结合pdb符号文件来找出bug所在)

minidump文件的创建方式:

1、父进程的所有线程都将挂起,并记录进程的“快照”。

2、快照包括加载到进程中的所有 DLL 模块的名称和版本,以及在进程中工作的线程列表。

3、对于其中每个线程,都会记录调用堆栈映像。

4、此外,有关操作系统版本、CPU 数量及其品牌名称的信息将写入小型转储文件。

5、 小型转储通常是在 DbgHelp DLL 的 MiniDumpWriteDump()函数的帮助下创建的。

6、有关 MiniDumpWriteDump()函数的其他信息,请参阅 MSDN。

 CrashRpt 生成一个 XML 崩溃描述文件 (crashrpt.xml) 来补充小型转储。

XML文件包含各种信息,如应用程序名称和版本,发件人的电子邮件地址和地理位置,用户提供的问题描述,异常类型和地址等。

自定义文件,例如应用程序日志文件,桌面屏幕截图和屏幕捕获视频,可以通过CrashRpt提供的API功能包含在崩溃报告中。

编译CrashRpt

默认情况下,CrashRpt 存档的 bin 目录包含在 Visual Studio 2010 中编译的二进制文件。这些文件仅用于演示目的。强烈建议您使用Visual Studio版本自行编译CrashRpt。这是确保 CrashRpt 使用与应用程序相同版本的 C 运行时库 (CRT) 所必需的。

CrashRpt 发行版的顶级目录包含 Visual Studio 2010 (CrashRpt_vs2010.sln) 的解决方案文件。 打开此解决方案文件以在 Visual C++ 2010 或 Visual C++ Express 2010 中编译 CrashRpt。

不是以上版本的编译器则需进行转换,笔者的编译器是Visual Studio 2022需要使用CMake工具进行转换,步骤如下:

1、下载 CMake(版本 2.8 或更高版本)并安装它。

2、照图填好路径(你下载的CrashRpt文件夹位置),进行操作:

Configure配置: 

完成后你就可以会看到生成的 CrashRpt.sln 文件,您可以使用该文件编译 CrashRpt(在 Visual Studio 中打开它)。 

解决方案结构

打开项目文件后我们可以看到以下的工程:

ConsoleDemo是一个控制台应用程序,有助于测试CrashRpt如何与控制台应用程序一起工作。

CrashRpt 项目包含 API 实现,并提供拦截异常的功能。

CrashRptProbe项目包含处理错误报告的功能。

CrashSender项目包含用于显示GUI,发送错误报告和显示错误报告发送进度的功能。

crprober是用于错误报告处理的控制台工具。

jpeg项目包含 JPEG 文件管理功能。

libogg项目包含OGG视频容器管理功能(与libtheora一起使用)。

libpng项目包含 PNG 文件管理功能。

libtheora项目包含 OGG Theora 视频编解码器功能。

MFCDemo是一个 GUI 应用程序,可帮助测试 CrashRpt API 函数是否与基于 MFC 的应用程序按预期工作。

minizip项目包含ZIP文件管理功能。

Tests包含自动测试功能。

tinyxml项目包含XML文件管理功能。

WTLDemo是一个GUI应用程序,有助于测试CrashRpt API函数是否与基于WTL的应用程序一起按预期工作。

Zlib项目包含文件压缩功能。

直接重新编译整个项目即可,编译完成后,可以在 bin 目录中找到 CrashRpt 可执行文件,可以在 lib 目录中找到库文件。

以下文件是最重要的:

bin\CrashRptXXXX.dll - 这是 CrashRpt 崩溃处理程序模块;

bin\CrashSenderXXXX.exe - 这是崩溃报告发送器模块;

lib\CrashRptXXXX.lib - 这是 CrashRpt 导入库。

上面,XXXX 占位符是 CrashRpt 的版本号。

Debug, Release and Release LIB编译配置

一般情况下以Release方式编译 CrashRpt,在此配置中,生成可在生产环境中使用的二进制文件。

Debug方式编译 CrashRpt,用于 CrashRpt 调试,不应用于生产模式,在此配置中,生成生成 d 后缀文件,例如 CrashRptXXXXd.dll、CrashSenderXXXXd.exe。

Release LIB 配置是对Debug, Release生成配置的补充。通常,您应该以Release方式编译 CrashRpt,但如果使用静态 CRT 链接,则需要以Release LIB 编译。在Release LIB配置中,编译生成CrashSenderXXXX.exe可执行文件和CrashRptLIB.lib静态库。 在此配置中,CrashSenderXXXX.exe 和 CrashRptLIB.lib 使用静态链接到 CRT。

一个使用CrashRpt的例子

 以下示例演示如何使用 CrashRpt API 函数和结构在控制台C++应用程序中启用崩溃报告支持。

项目配置

一般我们需要拷贝CrashRpt中的include目录和bin目录、lib目录中生成的文件到自己的项目中.

我的例子目录是这样组织的:

include目录配置:

lib目录配置:

lib文件配置:

注意这里的是导入库(为了更方便的使用dll)不是静态链接库.

增加一个 编译生成后事件,来自动拷贝bin目录和config目录下的文件:

一些其他项目配置:

请务必将Release配置中使用 CRT 作为多线程 DLL (/MD),这是 MSDN 中推荐的方法,也是项目默认配置。

对所有应用模块使用相同的 CRT 版本

 确保应用程序中存在的所有模块都使用相同的 CRT 版本,如果某些依赖模块是使用较旧版本的 CRT 编译的,则应重新编译它们以确保使用单个版本或 CRT DLL。例如,假设您使用 Visual Studio 2008 和 CRT 9.0 作为 DLL 链接,但应用程序中的某些依赖模块是在 Visual Studio 2005 中编译的,并使用链接为 DLL 的 CRT 8.0。在这种情况下,依赖模块中的 CRT 错误不会被 CrashRpt 截获,因为错误处理程序仅适用于 CRT 9.0。

Release配置启用程序数据库

为了能够从崩溃小型转储中恢复堆栈跟踪,调试器需要应用程序的调试符号(PDB 文件)。若要启用 PDB 文件的生成,请执行以下操作:

 

 应对解决方案中所有工程都进行以上设置

禁用省略帧指针优化

我们建议在发布版本配置中关闭省略帧指针 (FPO) 优化,因为此优化并没有真正带来明显的收益,但会使转储分析变得非常复杂。/Oy编译器选项使使用调试器更加困难,因为编译器禁止显示帧指针信息 。此外,在Visual Studio 2010中,默认情况下禁用此优化。

示例源代码

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <stdarg.h>
#include "CrashRpt.h"// 应用程序日志文件句柄
FILE* g_hLog = NULL;// 程序崩溃时的回调函数
int CALLBACK CrashCallback(CR_CRASH_CALLBACK_INFO* pInfo)
{// 应用程序崩溃了!// 关闭日志文件,避免日志文件一直被客户程序占用// 确保CrashRpt能够有Read权限把他包含到错误报告中if (g_hLog != NULL){// 关闭句柄fclose(g_hLog);g_hLog = NULL;}// 返回CR_CB_DODEFAULT以生成错误报告return CR_CB_DODEFAULT;
}// 写日志
void log_write(int num_args, LPCTSTR szFormat, ...)
{if (g_hLog == NULL)return;va_list args;va_start(args, num_args);_vftprintf_s(g_hLog, szFormat, args);fflush(g_hLog);
}// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{crInstallToCurrentThread2(0);log_write(1, _T("Entering the thread proc\n"));while (true){int* p = NULL;*p = 13;         // 这里会引发非法访问异常(Access Violation)}log_write(1, _T("Leaving the thread proc\n"));crUninstallFromCurrentThread();return 0;
}// 安装CrashRpt
bool InstallCrashRpt()
{// 定义CrashRpt配置参数CR_INSTALL_INFO info;memset(&info, 0, sizeof(CR_INSTALL_INFO));info.cb = sizeof(CR_INSTALL_INFO);// 应用程序名称info.pszAppName = _T("MyApp");// 应用程序版本info.pszAppVersion = _T("1.0.0");// 邮件主题info.pszEmailSubject = _T("MyApp 1.0.0 Error Report");// 崩溃日志收件地址info.pszEmailTo = _T("myapp_support@hotmail.com");// 崩溃日志应该上传的服务器info.pszUrl = _T("http://myapp.com/tools/crashrpt.php");info.uPriorities[CR_HTTP] = 3;  // 首先使用HTTP发送错误报告info.uPriorities[CR_SMTP] = 2;  // 其次使用SMTP发送错误报告info.uPriorities[CR_SMAPI] = 1; // 然后使用Simple MAPI发送错误报告// 对所有可能出现的异常进行处理info.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS;// 崩溃时重启程序info.dwFlags |= CR_INST_APP_RESTART;// 对以前未发送成功的错误报告,CrashRpt应该进行发送操作info.dwFlags |= CR_INST_SEND_QUEUED_REPORTS;// 程序重启命令行info.pszRestartCmdLine = _T("/restart");// 定义隐私策略网址info.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);return false;}return true;
}// 添加CrashRpt功能
void AddCrashRptFunction()
{crSetCrashCallback(CrashCallback, NULL);// 增加日志文件到错误报告中crAddFile2(_T("log.txt"), NULL, _T("Log File"), CR_AF_MAKE_FILE_COPY);// 增加整个桌面的截图到崩溃报告文件中crAddScreenshot2(CR_AS_VIRTUAL_SCREEN, 0);// 将命名属性添加到崩溃说明 XML 文件中crAddProperty(_T("VideoCard"), _T("nVidia GeForce 8600 GTS"));
}// 卸载CrashRpt
void UninstallCrashRpt()
{// 在主线程退出前卸载CrashRptcrUninstall();
}int _tmain(int argc, _TCHAR* argv[])
{// 安装CrashRptif (!InstallCrashRpt())// 安装失败return 1;// 添加CrashRpt功能AddCrashRptFunction();// 打开日志文件errno_t err = _tfopen_s(&g_hLog, _T("log.txt"), _T("wt"));if (err != 0 || g_hLog == NULL){// 不能打开日志文件_tprintf_s(_T("Error opening log.txt\n"));return 1;}log_write(1, _T("Started successfully\n"));// 创建工作线程HANDLE hWorkingThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)NULL, 0, NULL);log_write(1, _T("Created working thread\n"));// 这里会引发无效参数异常TCHAR* szFormatString = NULL;_tprintf_s(szFormatString);// 等待工作线程退出WaitForSingleObject(hWorkingThread, INFINITE);log_write(1, _T("Working thread has exited\n"));// 关闭日志文件if (g_hLog != NULL){// 关闭日志文件句柄fclose(g_hLog);g_hLog = NULL;}// 退出时卸载CrashRptUninstallCrashRpt();return 0;
}

修改CrashRpt界面语言

默认的CrashRpt是英语界面的,我们可以将CrashRpt根目录下的lang_files目录下的crashrpt_lang_ZH-CN.ini重命名为crashrpt_lang.ini,替换我们项目里的同名文件即可,就可以让界面显示为中文了。


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

相关文章

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属…

用卷积公式计算“独立随机变量之和”的概率分布 Distribution of sum of independent Rayleigh random variables

https://math.stackexchange.com/questions/1019375/distribution-of-sum-of-independent-rayleigh-random-variables

信号处理的卷积公式

《信号与系统》关于卷积的公式&#xff1a; 离散 序列卷积和 周期卷积 循环卷积 连续 卷积积分

卷积基本计算公式

1. 理论公式 2. tensorflow中使用 输入图片大小 WW Filter大小 FF 步长strides S padding的像素数 P 输出大小为NxNpadding “SAME”时&#xff0c;会在图像的周围填 “0”&#xff0c;padding “VALID”则不需要&#xff0c;即 P0。一般会选“SAME”&#xff0c;以来减缓图…

卷积公式的理解,卷积其实就是叠加与衰减。

对于初学者&#xff0c;我推荐用复利的例子来理解卷积可能更直观一些&#xff1a; 小明存入100元钱&#xff0c;年利率是5%&#xff0c;按复利计算&#xff08;即将每一年所获利息加入本金&#xff0c;以计算下一年的利息&#xff09;&#xff0c;那么在五年之后他能拿到的钱数…