c#全局异常捕获程序崩溃,c++程序崩溃原因
Yyds干货库存
@[目录]
1.简介不是所有的bug都能在发布前发现,也就是说不是所有抛出异常的bug都能在发布前发现。好在微软在平台SDK中包含了一个功能,可以帮助开发者收集用户发现的异常信息。MiniDumpWriteDump函数将必要的故障转储信息写入文件,而不保存整个进程空间。这个崩溃转储信息文件称为小型转储。这篇技术文章提供了关于如何编写和使用小型转储的信息。
1.1 MiniDumpWriteDump函数minidump函数为应用程序提供了一种生成包含整个进程上下文的有用子集的崩溃转储文件的方法;这称为小型转储文件。以下函数用于小型转储文件。将用户模式小型转储信息写入指定文件。
MiniDumpCallbackMiniDumpReadDumpStreamMiniDumpWriteDumpBOOL MiniDumpWriteDump([in]HANDLE hProcess,[in] DWORD ProcessId,[in] HANDLE hFile,[in] MINIDUMP_TYPE DumpType,[in]PMINIDUMP _ EXCEPTION _ INFORMATION EXCEPTION param,[in]PMINIDUMP _ USER _ STREAM _ INFORMATION userstream param,[in]PMINIDUMP _ CALLBACK _ INFORMATION CALLBACK param);Font color=green如果可能,应该从单独的进程中调用MiniDumpWriteDump,而不是从转储的目标进程中调用。当目标进程不稳定时尤其如此。例如,如果它只是崩溃。加载程序死锁是从目标进程调用MiniDumpWriteDump的许多潜在副作用之一。
Color=grey minidumpwritedump是DBGHELP库的一部分。此库不是线程安全的,因此任何使用MiniDumpWriteDump的程序都应该在尝试调用MiniDumpWriteDump之前同步所有线程。请注意,MiniDumpWriteDump目前不适用于托管代码,仅适用于Windows XP、Windows Vista和Windows 7。
Font=blue minidumpwritedump可能不会为调用线程生成有效的堆栈跟踪。要解决此问题,您必须在调用MiniDumpWriteDump之前捕获调用线程的状态并将其用作ExceptionParam参数。一种方法是在try/except块中强制异常,并使用GetExceptionInformation提供的EXCEPTION_POINTERS信息。或者,您可以从新的工作线程调用该函数,并从转储中过滤该工作线程。
1.2 Visual Studio分析小型转储打开Visual Studio。在“文件”菜单上,单击“打开项目”。将文件类型设置为转储文件,导航到转储文件,选择它,然后单击打开。运行调试器。调试器将创建一个模拟进程。模拟过程将在导致崩溃的指令处停止。1.3使用Microsoft Public Symbol Server获取驱动程序级或系统级的崩溃堆栈,您可能需要将Visual Studio配置为指向Microsoft Public Symbol Server。
在“调试”菜单上,单击“选项”。在“选项”对话框中,打开“调试”节点并单击符号。确保仅当未选择手动加载符号时才搜索上述位置,除非您希望在调试时手动加载符号。如果在远程符号服务器上使用符号,可以通过指定可以复制符号的本地目录来提高性能。为此,请输入从符号服务器到此目录的缓存符号路径。若要连接到Microsoft公共符号服务器,您需要启用此设置。请注意,如果在远程计算机上调试程序,缓存目录指的是远程计算机上的目录。单击确定。因为您使用的是Microsoft public symbol server,所以将出现一个最终用户许可协议对话框。单击“是”接受协议并将符号下载到本地缓存。1.4使用WinDbg调试小型转储您还可以使用WinDbg(作为Windows调试工具一部分的调试器)调试小型转储。WinDbg允许您不使用Visual Studio进行调试。要下载Windows调试工具,请参考Windows硬件开发人员中心上的Windows调试工具。
安装Windows操作系统操作系统调试工具后,必须在WinDbg中输入符号路径。在WinDbg中输入符号路径在文件菜单上,单击符号路径。在符号搜索路径窗口中,输入以下内容:
SRV * c:\ cache * https://msdl。微软。com/download/symbols;
2、代码实现
PDB(程序数据库),意即程序的基本数据,是对编译链接时生成的文件106 .物理数据库文件主要存储了对调试程序时所需要的基本信息,主要包括源文件名、变量名、函数名、FPO(帧指针)、对应的行号等等。因为存储的是调试信息,所以一般情况下物理数据库文件是在调试模式下才会生成。在对中可以进行设置,在释放;排放;发布版本中也可以生成物理数据库文件。
在释放;排放;发布下设置两处地方即可生成物理数据库文件:
将如下代码在程序初始化的时候执行,等待程序运行崩溃。
在打开可执行程序的扩展名崩溃后,生成。倾销文件,将其拷贝至包含可执行程序的扩展名和物理数据库文件同一目录,使用可视化工作室打开倾销文件,即可进行调试。
2.1 例子一
#包括输入输出流
#包含Windows.h
#包含Dbghelp.h
#包含strsafe.h
#包含时间。h
#包含shellapi.h
#包含shlobj.h
int生成的转储(异常指针*异常指针)
BOOL bMiniDumpSuccessful
WCHAR SZ路径[MAX _ PATH];
WCHAR SZ文件名[MAX _ PATH];
const WCHAR * SZ appname=L appname ;
const WCHAR * szVersion=L v1.0
DWORD dwBufferSize=MAX _ PATH
处理hDumpFile
系统时间
MINIDUMP _ EXCEPTION _ INFORMATION ExpParam;
GetLocalTime(stLocalTime);
GetTempPath(dwBufferSize,SZ path);
stringchprintf(SZ filename,MAX_PATH,L%s%s ,szPath,SZ appname);
CreateDirectory(szFileName,NULL);
stringchprintf(SZ filename,max_path,l%s%s\\%s-ddd-ddd-%ld-%ld.dmp,
szPath,szAppName,szVersion,
stLocalTime.wYear,stLocalTime.wMonth,stLocalTime.wDay,
stLocalTime.wHour,stLocalTime.wMinute,stLocalTime.wSecond,
GetCurrentProcessId()、GetCurrentThreadId());
hDumpFile=create file(SZ文件名,GENERIC_READ GENERIC_WRITE,
FILE _ SHARE _ WRITE FILE _ SHARE _ READ,0,CREATE_ALWAYS,0,0);
展示图.ThreadId=GetCurrentThreadId();
展示图.异常指针=pexception指针;
展示图.客户端指针=真
bMiniDumpSuccessful=MiniDumpWriteDump(GetCurrentProcess(),GetCurrentProcessId(),
hDumpFile,MiniDumpWithDataSegs,ExpParam,NULL,NULL);
返回异常执行处理程序;
void SomeFunction()
_ _尝试
int * pBadPtr=NULL
* pBadPtr=0;
_ _ except(生成的转储(getexception information()))
}
2.2 例子二
MiniDumper.h:
#ifndef MINIDUMPER_H
#定义MINIDUMPER_H
#包含windows.h
CMiniDumper类
{
公共:
CMiniDumper(bool bPromptUserForMiniDump);
~ CMiniDumper(void);
私人:
静态长WINAPI unhandledexception handler(struct _ EXCEPTION _ POINTERS * PE EXCEPTION info);
void setMiniDumpFileName(void);
bool getImpersonationToken(HANDLE * phToken);
BOOL使能特权(LPCTSTR pszPriv,HANDLE hToken,TOKEN _ PRIVILEGES * pt pold);
BOOL恢复权限(HANDLE hToken,TOKEN _ PRIVILEGES * pt pold);
LONG writeMiniDump(_ EXCEPTION _ POINTERS * PE EXCEPTION info);
_ EXCEPTION _ POINTERS * m _ PE EXCEPTION info;
TCHAR m _ szMiniDumpPath[MAX _ PATH];
TCHAR m _ szAppPath[MAX _ PATH];
TCHAR m _ szAppBaseName[MAX _ PATH];
bool m _ bPromptUserForMiniDump
静态CMiniDumper * s _ pMiniDumper
静态LP critical _ SECTION s _ pCriticalSection;
};
#endif //MINIDUMPER_H
- MiniDumper.cpp:
` ` cpp
#包含windows.h
#包含标准视频
#include assert.h
#包含时间。h
#包含标准库
#包含strsafe.h
//#包含查尔. h
#包含dbghelp.h
#包含" miniDumper.h "
#ifdef UNICODE
# define _ tcssprintf wsprintf
#定义tcsplitpath _wsplitpath
#否则
#define _tcssprintf sprintf
#define tcsplitpath _splitpath
#endif
const int USER _ DATA _ BUFFER _ SIZE=4096;
//-
//全局
//-
CMiniDumper * CMiniDumper:s _ pMiniDumper=NULL;
LP critical _ SECTION cmini dumper:s _ pCriticalSection=NULL;
//基于dbghelp.h
typedef BOOL(WINAPI * MINIDUMPWRITEDUMP)(处理h进程,
DWORD dwPid,
处理hFile,
小型转储类型,
CONST PMINIDUMP _ EXCEPTION _ INFORMATION异常参数,
CONST PMINIDUMP _ USER _ STREAM _ INFORMATION USER STREAM param,
CONST PMINIDUMP _ CALLBACK _ INFORMATION回调参数);
//-
//Name: CMiniDumper()
//Desc:构造函数
//-
CMiniDumper:CMiniDumper(bool bPromptUserForMiniDump)
//我们的CMiniDumper应该作为一个一个单独操作。
断言(!s _ pMiniDumper);
s _ pMiniDumper=this
m _ bpromtuserforminidump=bpromtuserforminidump;
SetUnhandledExceptionFilter函数使应用程序能够
//取代每个线程和进程的顶级异常处理程序。
//调用此函数后,如果进程中出现异常
//没有被调试,并且该异常导致
//未处理的异常筛选器,该筛选器将调用异常
//由lptoplevelexexceptionfilter参数指定的筛选函数。
* setunhandledexception filter(unhandledExceptionHandler);
//因为DBGHELP.dll本身不是线程安全的,所以调用它
//同时来自多个线程可能会产生未定义的行为。
//这意味着如果您的应用程序有多个线程,或者是
//由多个线程以非同步方式调用,您需要
//确保所有打到DBGHELP.dll的电话都通过全球
//临界区。
s _ pCriticalSection=new CRITICAL _ SECTION;
if( s_pCriticalSection)
InitializeCriticalSection(s _ pCriticalSection);
//-
//Name: ~CMiniDumper()
//Desc:析构函数
//-
CMiniDumper:~CMiniDumper( void)
if( s_pCriticalSection)
DeleteCriticalSection(s _ pccriticalsection);
删除s _ pCriticalSection
//-
//Name:unhandledExceptionHandler()
//Desc:用于未处理异常的回调过滤器函数
//-
LONG cmini dumper:unhandledExceptionHandler(_ EXCEPTION _ POINTERS * PE EXCEPTION info)
如果(!s_pMiniDumper)
返回异常_继续_搜索;
返回s _ pMiniDumper-writeMiniDump(PEX exception info);
//-
//Name: setMiniDumpFileName()
//Desc:
//-
void CMiniDumper:setMiniDumpFileName(void)
时间_t当前时间;
时间(tTime);
wsprintf( m_szMiniDumpPath,
L%s%s.%ld.dmp ,
m_szAppPath,
m_szAppBaseName,
当前时间);
//-
//Name: getImpersonationToken()
//Desc:该方法是一种潜在的解决方法,因为
//当前线程可能没有分配给它的标记,如果没有,则
//收到进程令牌。
//-
bool CMiniDumper:getImpersonationToken(HANDLE * phToken)
* phToken=NULL
如果(!OpenThreadToken(GetCurrentThread(),
令牌查询令牌调整权限,
没错,
phToken))
if(GetLastError()==ERROR _ NO _ TOKEN)
//当前线程没有可用的模拟标记。
//让我们改用进程标记。
如果(!OpenProcessToken(GetCurrentProcess(),
令牌查询令牌调整权限,
phToken))
返回错误的
其他
返回错误的
返回真实的
//-
//Name: enablePrivilege()
//Desc:因为小型转储包含许多关于操作系统的元数据
//转储时的应用程序状态,这是一个相当特权的
//操作。这意味着我们需要设置权限以便能够
//调用MiniDumpWriteDump .
//-
BOOL CMiniDumper:enable privilege(LPCTSTR pszPriv,HANDLE hToken,TOKEN_PRIVILEGES* ptpOld)
布尔博克=假
令牌_特权tp
tp .PrivilegeCount=1;
tp .权限[0]。属性=SE _特权_已启用
bOk=LookupPrivilegeValue( 0,pszPriv,tp .权限[0]。luid);
如果(确定)
DWORD cbOld=sizeof(* pt pold);
bOk=AdjustTokenPrivileges(hto ken,FALSE,tp,cbOld,ptpOld,cbOld);
return(bOk(ERROR _ NOT _ ALL _ ASSIGNED!=GetLastError()));
//-
//Name: restorePrivilege()
//Desc:
//-
BOOL cmini dumper:restore特权(HANDLE hToken,TOKEN_PRIVILEGES* ptpOld)
BOOL bOk=AdjustTokenPrivileges(hToken,FALSE,ptpOld,0,NULL,NULL);
return(bOk(ERROR _ NOT _ ALL _ ASSIGNED!=GetLastError()));
//-
//Name: writeMiniDump()
//Desc:
//-
LONG CMiniDumper:writeMiniDump(_ EXCEPTION _ POINTERS * PE EXCEPTION info)
LONG retval=EXCEPTION _ CONTINUE _ SEARCH;
m _ p exception info=p exception info;
HANDLE hImpersonationToken=NULL;
如果(!getImpersonationToken(hImpersonationToken))
返回错误的
//你必须找到合适的dbghelp.dll .
//首先查看可执行程序的扩展名旁边的文件,因为系统32中的文件可能是旧的(Win2k)
HMODULE hDll=NULL
TCHAR szDbgHelpPath[MAX _ PATH];
if( GetModuleFileName( NULL,m_szAppPath,_MAX_PATH))
TCHAR * PS lash=wcsrchr(m _ szAppPath, \ \ );
中频(p flash)
_tcscpy( m_szAppBaseName,p flash 1);
*(PS lash 1)=0;
wcscpy( szDbgHelpPath,m _ szAppPath);
wcscat( szDbgHelpPath,L dbghelp。dll’);
hDll=:LoadLibrary(szDbgHelpPath);
if( hDll==NULL)
//如果我们还没有找到,再试一次。
hDll=:LoadLibrary(L dbghelp。dll’);
LPCTSTR szResult=NULL
中频(hDll)
//获取MiniDumpWriteDump函数的地址,该函数写道
//用户模式小型转储信息到指定文件。
MINIDUMPWRITEDUMP MINIDUMPWRITEDUMP=
(MINIDUMPWRITEDUMP):GetProcAddress(hDll, MINIDUMPWRITEDUMP );
if( MiniDumpWriteDump!=空)
TCHAR szScratch用户数据缓冲区大小];
setMiniDumpFileName();
//询问用户是否要保存小型转储文件.
wsprintf( szScratch,
出现意外错误:\ n \您愿意吗
我想创建一个迷你转储文件?\n\n%s ,
m _ szMiniDumpPath);
//创建小型转储文件.
HANDLE hFile=:创建文件(m _ szMiniDumpPath,
通用_写入
文件共享写入,
空,
创建_总是,
文件_属性_正常,
NULL);
if( hFile!=无效句柄值)
_ MINIDUMP _ EXCEPTION _ INFORMATION ex info;
ExInfo .ThreadId=:GetCurrentThreadId();
ExInfo .异常指针=pexception info
ExInfo .客户端指针=空
//我们需要权限才能运行MiniDumpWriteDump
令牌_特权tp
BOOL bprivilegenabled=enable privilege(SE _ DEBUG _ NAME,hImpersonationToken,TP);
布尔博克;
//DBGHELP.dll不是线程安全的,所以我们需要限制访问.
进入临界区(s _ PC critical section);
//将小型转储数据写入文件.
bOk=MiniDumpWriteDump(GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
小型转储正常,
ExInfo,
空,
NULL);
LeaveCriticalSection(s _ pccriticalsection);
//完成后恢复特权
if(bprivilegenabled)
restore特权(hImpersonationToken,TP);
如果(确定)
szResult=NULL
retval=EXCEPTION _ EXECUTE _ HANDLER;
其他
wsprintf( szScratch,
我未能将小型转储文件保存到“%s”(错误%d),
m_szMiniDumpPath,
GetLastError());
szResult=szScratch
*关闭句柄(hFile);
其他
wsprintf( szScratch,
我未能创建小型转储文件“%s”(错误%d),
m_szMiniDumpPath,
GetLastError());
szResult=szScratch
其他
对指针的调用未能找到MiniDumpWriteDump .
DBGHELP。动态链接库可能过时了。
其他
szResult=L "对加载库的调用未能找到DBGHELP。DLL .
if(SZ结果m _ bPromptUserForMiniDump)
MessageBox( NULL,szResult,NULL,MB _ OK);
termin ate process(GetCurrentProcess(),0);
返回返回值
test.cpp:
#包含" MiniDumper.h "
CMiniDumper g _ mini dumper(true);
2.3 例子三
MiniDump.h
#杂注一次
#包含Windows.h
#包含查尔. h
#包含DbgHelp.h
#杂注注释(lib, dbghelp.lib )
#ifdef UNICODE
#定义TSprintf wsprintf
#否则
#定义TSprintf sprintf
#endif
类小型转储
私人:
MiniDump();
~ MiniDump();
公共:
//程序崩溃时是否启动自动生成倾销文件;
//只需要在主要的函数开始处调用该函数即可;
静态void EnableAutoDump(bool be nable=true);
私人:
静态长应用崩溃处理程序(EXCEPTION _ POINTERS * PE EXCEPTION);
静态void create dump file(LPCWSTR lpstrdumpfilepaname,EXCEPTION _ POINTERS * PE EXCEPTION);
};
MiniDump.cpp
#包含" MiniDump.h "
小型转储:小型转储()
小型转储:~小型转储()
void MiniDump:enable auto dump(bool be nable)
if (bEnable)
setunhandledexception FILTER((LP top _ LEVEL _ EXCEPTION _ FILTER)ApplicationCrashHandler);
LONG MiniDump:ApplicationCrashHandler(EXCEPTION _ POINTERS * PE EXCEPTION)
/*if (IsDebuggerPresent())
返回异常_继续_搜索;
TCHAR szDumpDir[MAX _ PATH]={ 0 };
TCHAR szDumpFile[MAX _ PATH]={ 0 };
TCHAR szMsg[MAX _ PATH]={ 0 };
系统时间stTime={ 0 };
//构建倾销文件路径;
GetLocalTime(stTime);
* GetCurrentDirectory(MAX _ PATH,szDumpDir);
tsprintf(szdumpfile,_t(%s\\ddd_ddd.dmp),szdumpdir,
stTime.wYear,stTime.wMonth,stTime.wDay,
stTime.wHour,stTime .wm分钟,sttime。ws第二);
//创建倾销文件;
CreateDumpFile(szDumpFile,PE异常);
//弹出一个错误对话框或者提示上传,并退出程序;
TSprintf(szMsg,_T(很抱歉,程序崩溃了\ r \转储文件:%s )、szDumpFile);
fatalapexit(-1,szMsg);
返回异常执行处理程序;
void MiniDump:创建转储文件(LPCWSTR strPath,EXCEPTION _ POINTERS * pException)
//创建倾销文件;
HANDLE hDumpFile=CREATE FILE(strPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
//转储信息;
MINIDUMP _ EXCEPTION _ INFORMATION dumpInfo;
转储信息.ExceptionPointers=pException
转储信息.ThreadId=GetCurrentThreadId();
转储信息.客户端指针=真
//写入倾销文件内容;
MiniDumpWriteDump(GetCurrentProcess()、GetCurrentProcessId()、hDumpFile、MiniDumpNormal、dumpInfo、NULL、NULL);
CloseHandle(hDumpFile);
}
2.4 例子四
CrashRpt是一个免费的开源库,旨在拦截C程序中的异常、收集有关崩溃的技术信息并通过互联网向软件供应商发送错误报告。
http://号事故报告。SourceForge。net/docs/html/getting _ started。超文本标记语言
#包含windows.h
#包含标准视频
#包含查尔. h
//包含CrashRpt标头
#include CrashRpt.h
FILE * g _ hLog=NULL//应用程序日志文件的全局句柄
//定义崩溃时将调用的回调函数
(同Internationalorganizations)国际组织回调崩溃回调(CR_CRASH_CALLBACK_INFO* pInfo)
//应用程序已经崩溃!
//在此关闭日志文件
//确保CrashRpt能够将其包含到错误报告中
如果(g_hLog!=空)
fclose(g _ hLog);
g _ hLog=NULL//清理句柄
//返回CR _ CB _默认生成错误报告
返回CR _ CB _默认
//下面的函数将一个条目写入日志文件
void log_write(LPCTSTR szFormat,)
if (g_hLog==NULL)
返回;//日志文件似乎已关闭
虚拟设备列表参数;
va _ start(args);
_vftprintf_s(g_hLog,szFormat,args);
fflush(g _ hLog);
//线程过程
DWORD WINAPI线程进程(LPVOID lpParam)
//为此线程安装异常处理程序
crinstalltocurrentthread 2(0);
log_write(_T(进入线程proc \ n ));
//定义将进行某些处理的无限循环
for(;)
//循环内部某处有隐藏的错误.
int * p=NULL
* p=13//这会导致访问冲突
log_write(_T(离开线程proc \ n ));
//退出线程前取消设置异常处理程序
crUninstallFromCurrentThread();
返回0;
int _tmain(int argc,_TCHAR* argv[])
//定义CrashRpt配置参数
CR _安装信息信息
memset( info,0,sizeof(CR _ INSTALL _ INFO));
信息。CB=sizeof(CR _ INSTALL _ INFO);
信息。pszapname=_ T( MyApp );
信息。pszappversion=_ T( 1。0 .0 );
信息。pszemailpsubject=_ T( MyApp 1。0 .0错误报告);
信息。pszemailto=_ T( myapp _ support @ hotmail。com’);
信息。PSZ URL=_ T( http://myapp。com/tools/crash RPT。PHP’);
信息。uprights[CR _ HTTP]=3;//首先尝试通过超文本传送协议发送报告
信息。uprights[CR _ SMTP]=2;//第二次尝试通过简单邮件传输协议发送报告
信息。uprights[CR _ SMAPI]=1;//第三次尝试通过简单邮件应用程式接口(Mail Application Programming Interface)发送报告
//安装所有可用的异常处理程序
信息。dw标志=CR _ INST _所有_可能_处理程序;
//崩溃时重新启动应用程序
信息。dw flags =CR _ INST _ APP _ RESTART;
信息。dw标志=CR _ INST _发送_排队_报告;
信息。pszrestartcmdline=_ T(/restart );
//定义隐私策略统一资源定位器
信息。pszprivacypolicyurl=_ T( http://myapp。com/隐私政策。html’);
//安装崩溃报告
int n result=crInstall(info);
if(nResult!=0)
//出问题了。获取错误消息。
TCHAR szErrorMsg[512]=_ T();
crGetLastErrorMsg(szErrorMsg,512);
_tprintf_s(_T(%s\n ),szErrorMsg);
返回1;
//设置崩溃回调函数
crSetCrashCallback(崩溃回调,空);
//将日志文件添加到错误报告中
crAddFile2(_T(log.txt ),NULL,_T(Log File ),CR _ AF _ MAKE _ File _ COPY);
//我们希望在崩溃时添加整个桌面的截图
cradd截图2(CR _ AS _ VIRTUAL _ SCREEN,0);
//添加表示图形适配器的命名属性
//安装在用户的机器上
crAddProperty(_T(视频卡),_T(英伟达GeForce 8600 GTS’);
//主要代码如下.
//打开日志文件
errno_t err=_tfopen_s( g_hLog,_T(log.txt ),_ T( wt );
如果(呃!=0 g_hLog==NULL)
_tprintf_s(_T(打开log.txt\n ))错误;
返回1;//无法打开日志文件
log_write(_T(启动成功\ n ));
//创建工作线程
HANDLE hworking thread=CreateThread(NULL,0,
ThreadProc,(LPVOID)NULL,0,NULL);
log_write(_T(已创建工作线程\ n ));
主()函数中有隐藏的错误
//使用空参数调用_tprintf_s
TCHAR * szFormatString=NULL;
_ tprintf _ s(szFormatString);
//等待工作线程退出
WaitForSingleObject(hworking thread,无限);
log_write(_T(工作线程已退出\ n’);
//关闭日志文件
如果(g_hLog!=空)
fclose(g _ hLog);
g _ hLog=NULL//清理句柄
//退出主函数前取消CrashRpt的初始化
crUninstall();
//退出
返回0;
}
2.5 其他例子
(1)除了
CrashRpt,chromium 里使用的 crashpad 也是一个非常好的选择。google 出品,质量有保障。
crashpad 的前身是 breakpad。
https://github.com/chromium/crashpad
(2)适用于.NET程序的 CrashReporter。
https://github.com/ravibpatel/CrashReporter.NET
(3)其它平台(Android,iOS等)也有类似的开源库。可以在 github 上搜索 crash report。
3、调试工具
3.1 windbg
Windows 调试程序 (WinDbg) 可用于调试内核模式和用户模式代码、分析故障转储以及在代码执行时检查 CPU 寄存器。
https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/debugger-download-tools
从 SDK 获取用于 Windows (WinDbg) 的调试工具:Windows SDK。 使用Windows SDK 页上的下载链接,因为 Windows 调试工具在Visual Studio中不可用。
如果你只需要用于Windows的调试工具,而不是用于Windows的 (WDK) Windows 驱动程序工具包,则可以将调试工具安装为Windows软件开发工具包 (SDK) 的独立组件。
在 SDK 安装向导中选择“Windows 调试工具” ,并取消选择所有其他组件。
3.2 debugdiag
Debug Diagnostic Tool (DebugDiag)是微软提供的工具,可以用来追踪windows平台下的程序崩溃,卡死,内存泄漏等一些疑难问题的原因,按照问题类别配置收集后,反馈给公司技术人员。
下载后按缺省提示安装即可:
https://www.microsoft.com/en-US/download/details.aspx?id=58210
https://www.microsoft.com/en-us/download/details.aspx?id=49924
3.3 Visual Studio
转储文件是一个快照,其显示某个时间点正在为应用执行的进程和已为应用加载的模块。 带堆信息的转储还包括该时间点的应用内存的快照。
在 Visual Studio 中打开带堆的转储文件类似于在调试会话中在断点处停止。 尽管你无法继续执行,但在转储时可以检查应用的堆栈、线程和变量值。
转储最常用于调试开发人员无权访问的计算机中的问题。 当你无法在自己的计算机上重现崩溃或无响应的程序时,可以使用来自客户计算机的转储文件。 测试人员还会创建转储以保存崩溃或无响应程序数据,从而用于更多测试。
Visual Studio 调试器可为托管或本机代码保存转储文件。 它可以调试由 Visual Studio 或其他以小型转储格式保存文件的应用创建的转储文件。
利用VS可以很方便的分析dump文件,如果有生成dump文件时对应的.pdb文件,就可以直接定位到出错的代码行。
PDB (Program Data Base) 即程序的基本数据,是 VS 编译链接时生成的文件,每个程序集(EXE 或 DLL)都有一个与之对应的 PDB 文件。DPB 文件主要存储了 VS 调试程序时所需要的基本信息,主要包括源文件名、变量名、函数名、对应的行号等等。因为存储的是调试信息,所以一般情况下 PDB 文件是在 Debug 模式下才会生成。有了这个文件,我们才能对程序进行 断点调试 ,才能一步步执行程序。
如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。