#include <filesystem>
#include <windows.h>
#include <dbghelp.h>

#pragma comment(lib,"dbghelp.lib")

/// \brief 本模块在一个exe或dll中只需要执行一次，直接include本文件到main、App或程序初始化模块中，
/// 调用一次

/// 预先设置的dump文件路径
static wchar_t dumpFilePath[MAX_PATH] = { 0 };
/// 预先设置的创建dump文件方式
static MINIDUMP_TYPE dumpFlag = MiniDumpWithFullMemory;

static LONG applicationCrashHandler_CreateDump(EXCEPTION_POINTERS* pException)
{
	time_t time_ = time(nullptr);
	std::tm t;
	localtime_s(&t, &time_);
	size_t len = wcslen(dumpFilePath); //预设路径长度
	_snwprintf_s(dumpFilePath + len, MAX_PATH - len, MAX_PATH - len, L"_%4.4d%2.2d%2.2d_%2.2d%2.2d%2.2d.dmp", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);

	// 创建Dump文件
	HANDLE hDumpFile = CreateFile(dumpFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	// Dump信息
	MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
	dumpInfo.ExceptionPointers = pException;
	dumpInfo.ThreadId = GetCurrentThreadId();
	dumpInfo.ClientPointers = TRUE;

	// 写入Dump文件内容
	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, dumpFlag, &dumpInfo, NULL, NULL);

	CloseHandle(hDumpFile);

	return EXCEPTION_EXECUTE_HANDLER;

}

/// @brief 设置崩溃时创建dump
/// @param path 设置dump途径和文件名前缀。例如设置为L"D:\XYZ"，则崩溃时创建的文件为D:\XYZ_<日期>_<时间>.dmp
/// @param flag 默认
static void setCreateDump(const wchar_t* path,
	int flag = MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithDataSegs | MiniDumpWithHandleData | MiniDumpWithThreadInfo)
{
	dumpFlag = MINIDUMP_TYPE(flag);
	//设置dump路径，与exe路径相同，增加日期时间（启动程序的时间，不是奔溃的时间，关系不大）
	wcscpy_s(dumpFilePath, std::size(dumpFilePath), path);

	SetUnhandledExceptionFilter(applicationCrashHandler_CreateDump);

}

/// @brief 测试崩溃是否能正常创建dump文件
static void TestDump()
{
    char *p = 0;
    *p = 1;
}
