一、背景介绍
当我们开发Windows应用程序时,难免会遇到崩溃的情况。而在排查崩溃问题时,我们通常需要使用Windbg
等调试工具来获取崩溃信息和分析堆栈。但是,如果我们想要自动化地捕获崩溃文件并进行分析,就需要编写一些代码来实现。
本文将介绍如何在Windows平台上使用C++编写自动截取崩溃文件
的代码,无需依赖Windbg工具。这个方法基于Windows平台下的MiniDump
机制,它是一种小型的Dump文件,只包含了崩溃时进程的关键信息,比完整的Dump文件更加轻量级,因此对分析崩溃问题非常有帮助。Windows系统提供了MinidumpWriteDump函数,可以生成MiniDump
文件。因此,我们可以利用该函数来实现自动截取崩溃文件的功能。
最后,本文将给出封装好的代码,只需在程序启动时调用StartDetectCrash
函数,程序退出时调用StopDetectCrash
函数,即可实现自动截取dmp崩溃文件。
二、实现过程
- 引入头文件
我们需要引入windows.h和dbghelp.h头文件,并且需要链接dbghelp.lib库。
#include <windows.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
- 设置
MiniDump
类型
我们需要设置MiniDump
的类型,以便在生成MiniDump
文件时包含足够的信息。在这里,我们选择了MiniDumpWithDataSegs,它包含了数据段的内容。MiniDump
的类型还有其他几种,可以根据自己的需要进行选择。
DWORD dwDumpType = MiniDumpWithDataSegs;
- 获取当前进程ID
我们需要获取当前进程的ID。
DWORD dwProcessId = GetCurrentProcessId();
- 获取当前进程句柄
我们需要获取当前进程的句柄。
HANDLE hProcess = GetCurrentProcess();
- 设置
MiniDump
文件名
在这里,我们使用了时间戳作为MiniDump
文件的名称,以便于区分不同的Dump文件。也可以根据自己的需要设置其他的文件名。
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
WCHAR szDumpFileName[MAX_PATH];
wsprintf(szDumpFileName, L"CrashDump_%04d-%02d-%02d_%02d-%02d-%02d.dmp",
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
- 打开
MiniDump
文件并写入Dump信息
我们需要打开MiniDump
文件并写入Dump信息。
HANDLE hFile = CreateFile(szDumpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION stExceptionInfo = { 0 };
stExceptionInfo.ThreadId = GetCurrentThreadId();
stExceptionInfo.ExceptionPointers = pException;
stExceptionInfo.ClientPointers = TRUE;
BOOL bWriteDump = MiniDumpWriteDump(hProcess, dwProcessId, hFile, dwDumpType, &stExceptionInfo, NULL, NULL);
if (bWriteDump)
{
printf("MiniDump file is generated: %ls\n", szDumpFileName);
}
else
{
printf("Failed to write MiniDump file: %ls\n", szDumpFileName);
}
CloseHandle(hFile);
}
else
{
printf("Failed to open MiniDump file: %ls\n", szDumpFileName);
}
- 注册异常处理函数
我们需要注册一个异常处理函数来处理程序崩溃的情况。在这里,我们使用了系统自带的SetUnhandledExceptionFilter函数来实现。当程序发生异常时,Windows会调用该异常处理函数,并传递一个指向EXCEPTION_POINTERS结构体的指针,该结构体包含了关于异常的详细信息。
LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* pException)
{
WCHAR szMessage[MAX_PATH];
wsprintf(szMessage, L"An unhandled exception (0x%08X) occurred at 0x%p.\n",
pException->ExceptionRecord->ExceptionCode,
pException->ExceptionRecord->ExceptionAddress);
OutputDebugString(szMessage);
GenerateMiniDump(pException);
return EXCEPTION_CONTINUE_SEARCH;
}
int main()
{
SetUnhandledExceptionFilter(ExceptionFilter);
// ...
}
至此,我们已经完成了自动截取崩溃文件的代码实现。在程序运行过程中,如果发生异常导致程序崩溃,将生成一个MiniDump
文件,以方便我们后续进行分析和排查问题。
三、代码封装
在程序启动时调用StartDetectCrash函数。
等待程序退出前,在适当的位置调用StopDetectCrash函数,停止崩溃检测并释放相关资源。
这样,程序就能够自动截取dmp崩溃文件了。例如,在以下示例中,我们进行了10秒计时,随后产生崩溃。
#include <iostream>
#include "DumpFileManager.h"
void DoSomething()
{
int count = 0;
while (count < 10)
{
Sleep(1000);
std::cout << "get tick count: " << count + 1 << std::endl;
++count;
}
throw "something error";
Sleep(10 * 1000);
std::cout << "DoSomething success"<< std::endl;
}
int main()
{
StartDetectCrash();
DoSomething();
StopDetectCrash();
return 0;
}
崩溃后,将在应用程序所在路径生成DumpFile文件夹,其中包含dmp崩溃文件和DumpFile.log日志文件。dmp崩溃文件名称为程序启动时间,DumpFile.log日志文件中有崩溃时间、内存、句柄等信息,例如:
2024-01-16 15:20:59.625: CrashMsg: WorkingSetSize:9856(kb),PagefileUsage:1872(kb),HandleCount:120!
崩溃文件的分析方法可以参考:https://www.cnblogs.com/idbeta/p/4992128.html
四、工程获取
如有任何疑问,请在评论区留言。
转载须经作者同意,且必须注明原作者及原文出处。任何未经授权的转载、摘编或使用本文内容,将依法追究其法律责任。