Windows C++ 自动截取dmp崩溃文件(无需部署windbg)

一、背景介绍

  当我们开发Windows应用程序时,难免会遇到崩溃的情况。而在排查崩溃问题时,我们通常需要使用Windbg等调试工具来获取崩溃信息和分析堆栈。但是,如果我们想要自动化地捕获崩溃文件并进行分析,就需要编写一些代码来实现。

  本文将介绍如何在Windows平台上使用C++编写自动截取崩溃文件的代码,无需依赖Windbg工具。这个方法基于Windows平台下的MiniDump机制,它是一种小型的Dump文件,只包含了崩溃时进程的关键信息,比完整的Dump文件更加轻量级,因此对分析崩溃问题非常有帮助。Windows系统提供了MinidumpWriteDump函数,可以生成MiniDump文件。因此,我们可以利用该函数来实现自动截取崩溃文件的功能。

  最后,本文将给出封装好的代码,只需在程序启动时调用StartDetectCrash函数,程序退出时调用StopDetectCrash函数,即可实现自动截取dmp崩溃文件。

二、实现过程

  1. 引入头文件

  我们需要引入windows.h和dbghelp.h头文件,并且需要链接dbghelp.lib库。

#include <windows.h>
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
  1. 设置MiniDump类型

  我们需要设置MiniDump的类型,以便在生成MiniDump文件时包含足够的信息。在这里,我们选择了MiniDumpWithDataSegs,它包含了数据段的内容。MiniDump的类型还有其他几种,可以根据自己的需要进行选择。

DWORD dwDumpType = MiniDumpWithDataSegs;
  1. 获取当前进程ID

  我们需要获取当前进程的ID。

DWORD dwProcessId = GetCurrentProcessId();
  1. 获取当前进程句柄

  我们需要获取当前进程的句柄。

HANDLE hProcess = GetCurrentProcess();
  1. 设置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);
  1. 打开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);
}
  1. 注册异常处理函数

  我们需要注册一个异常处理函数来处理程序崩溃的情况。在这里,我们使用了系统自带的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

四、工程获取

【点击下载】github: DumpFileManager

如有任何疑问,请在评论区留言。

转载须经作者同意,且必须注明原作者及原文出处。任何未经授权的转载、摘编或使用本文内容,将依法追究其法律责任。

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值