#include "cpp_err.h"
#include <string>

#ifdef _MSC_VER
#include "windows.h"
#include "DbgHelp.h"
#endif

void stackoverflow() 
{
	// 1.线程栈空间有上限: windows 默认:1MB,Linux默认 2MB。
	// 2.当前线程占用栈空间大小:线程函数调用堆栈中各个函数占用的栈空间总和。
	// 3.哪些对象占用了栈空间:
	//		(1)函数局部变量
	//		(2)调用函数的参数
	// 4.常见引发栈溢出的原因:
	//		(1)递归太深
	//		(2)局部变量占用太大
	//		(3)switch-case case分支过多。
	//		(4)死循环调用
	// 5.发生线程栈溢出时,VS可能直接退出,无法看到调用堆栈,可以使用WinDBG查看。
}

#ifdef _MSC_VER
int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers, const std::string& dump_dir)
{
	// 定义函数指针
	typedef BOOL(WINAPI * MiniDumpWriteDumpT)(
		HANDLE,
		DWORD,
		HANDLE,
		MINIDUMP_TYPE,
		PMINIDUMP_EXCEPTION_INFORMATION,
		PMINIDUMP_USER_STREAM_INFORMATION,
		PMINIDUMP_CALLBACK_INFORMATION
		);
	// 从 "DbgHelp.dll" 库中获取 "MiniDumpWriteDump" 函数
	MiniDumpWriteDumpT pfnMiniDumpWriteDump = NULL;
	HMODULE hDbgHelp = LoadLibrary("DbgHelp.dll");
	if (NULL == hDbgHelp)
	{
		return EXCEPTION_CONTINUE_EXECUTION;
	}
	pfnMiniDumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");

	if (NULL == pfnMiniDumpWriteDump)
	{
		FreeLibrary(hDbgHelp);
		return EXCEPTION_CONTINUE_EXECUTION;
	}
	// 创建 dmp 文件
    char path_buffer[512]{};
    char szVersion[] = "DumpDemo_v1.0";
	SYSTEMTIME stLocalTime;
	GetLocalTime(&stLocalTime);
	std::snprintf(path_buffer, sizeof(path_buffer), "%s\\%s-%04d%02d%02d-%02d%02d%02d.dmp", dump_dir.c_str(),
		szVersion, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
		stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
	HANDLE hDumpFile = CreateFile(path_buffer, GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
	if (INVALID_HANDLE_VALUE == hDumpFile)
	{
		FreeLibrary(hDbgHelp);
		return EXCEPTION_CONTINUE_EXECUTION;
	}
	// 写入 dmp 文件
	MINIDUMP_EXCEPTION_INFORMATION expParam;
	expParam.ThreadId = GetCurrentThreadId();
	expParam.ExceptionPointers = pExceptionPointers;
	expParam.ClientPointers = FALSE;
	pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
		hDumpFile, MiniDumpWithDataSegs, (pExceptionPointers ? &expParam : NULL), NULL, NULL);
	// 释放文件
	CloseHandle(hDumpFile);
	FreeLibrary(hDbgHelp);
	return EXCEPTION_EXECUTE_HANDLER;
}

LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo)
{
	// 这里做一些异常的过滤或提示
	if (IsDebuggerPresent())
	{
		return EXCEPTION_CONTINUE_SEARCH;
	}
	return GenerateMiniDump(lpExceptionInfo, "D:\\");
}
// windows cpp 崩溃使用 windbg 调试
void use_windbg()
{
    SetUnhandledExceptionFilter(ExceptionFilter);
}
#endif