SetUnhandledExceptionFilter回调中不可直接调用MiniDumpWriteDump,因栈损坏、堆不一致、CRT不可重入易致二次崩溃;应预缓存路径等POD数据,仅保存上下文后跳转安全区;需启用MiniDumpWithFullMemory等关键flag并用CreateFileW确保写入成功。

直接用 SetUnhandledExceptionFilter 捕获崩溃并调用 MiniDumpWriteDump 生成有效 dump 文件,是 Windows 下最轻量、最可控的崩溃采集方式——但默认行为几乎必然失败:dump 文件为空、缺失堆栈、无法加载符号,甚至根本写不出文件。
为什么 SetUnhandledExceptionFilter 回调里不能直接调用 MiniDumpWriteDump
SEH 异常发生时,线程栈可能已损坏、堆分配器可能处于不一致状态、CRT 的 malloc/free 可能不可重入。此时若调用 MiniDumpWriteDump(它内部会 malloc、打开文件、遍历模块),极易二次崩溃或静默失败。
- 不要在异常回调中做任何堆分配、文件 I/O、字符串格式化、CRT 函数调用
- 所有路径、文件名、模块信息必须提前缓存为全局 POD 数据(如
char g_dumpPath[MAX_PATH]) - 推荐只做三件事:保存当前线程上下文(
GetThreadContext)、记录关键寄存器值、跳转到一个干净的、预分配栈空间的「安全区」
如何让 MiniDumpWriteDump 写出可调试的完整 dump
默认 flags(如 MiniDumpNormal)只保存极简信息,VS 打开后看不到堆栈、局部变量、甚至无法识别模块。必须显式启用关键 flag:
-
MiniDumpWithFullMemory:抓全进程内存(体积大但调试必备;若担心大小,可用MiniDumpWithPrivateReadWriteMemory+MiniDumpWithDataSegs折中) -
MiniDumpWithHandleData:记录句柄表,排查资源泄漏有用 -
MiniDumpWithUnloadedModules:捕获已卸载但仍在调用栈里的 DLL(常见于热更新/插件场景) -
MiniDumpWithIndirectlyReferencedMemory:对指针密集型程序(如游戏引擎)很重要,否则局部变量里的对象地址指向的内存不会被包含
示例调用:
在 Windows 11 上"直接发声"的 TTS(从 WSL2/TUI 调用 powershell.exe + System.Speech)。适用于用户说"说出来/读出来/语音播报/用TTS",或反馈"没声音/tts 生成的 mp3 是空的/播不出来",以及需要中文语音但 OpenClaw 内置 tts 不可用时。
立即学习“C++免费学习笔记(深入)”;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
MiniDumpWithFullMemory | MiniDumpWithHandleData |
MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory,
&excptInfo, nullptr, nullptr);
崩溃时文件写入失败的三个硬坑
即使 dump 逻辑正确,90% 的「写不出文件」问题都卡在这三点:
- 路径含中文或空格且未用宽字符 API:必须用
CreateFileW而非CreateFileA,传L"C:\crash\dump.dmp" - 目标目录不存在且程序无权创建:崩溃前不检查目录,异常时
CreateFileW直接返回INVALID_HANDLE_VALUE;应提前创建好目录(如启动时调用CreateDirectoryW) - 杀毒软件拦截:部分 AV 会 hook
CreateFileW并拒绝「可疑进程」创建 dump 文件;临时方案是改用GetCurrentProcessId()+ 时间戳命名,并把路径设在%LOCALAPPDATA%下
真正有效的 MiniDump 不是靠堆栈深度或参数堆砌,而是靠「异常发生前就准备好一切,异常发生后只做最原始的系统调用」——路径、句柄、上下文、flags,全部预置;写文件只调一次 CreateFileW 和 MiniDumpWriteDump;其余逻辑全部砍掉。稍有犹豫,dump 就废了。

















