鳗鱼丫头 發表於 2026-1-11 09:14:05

vs2019+qt工程中如何生成dump文件及调试详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>一、调试前置条件</li><li>二、抓取异常的系统函数区分</li><li>三、可直接复用的代码:</li><li>四、调试:</li><li>总结</li></ul></div><p class="maodian"></p><h2>一、调试前置条件</h2>
<p>1、在编译之后,exe和pdb文件均需要发布给用户;</p>
<p class="maodian"></p><h2>二、抓取异常的系统函数区分</h2>
<div class="jb51code"><pre class="brush:cpp;">AddVectoredExceptionHandler和SetUnhandledExceptionFilter
</pre></div>
<blockquote><p>AddVectoredExceptionHandler 是&ldquo;第一现场观察者&rdquo;,<br />SetUnhandledExceptionFilter 是&ldquo;最后兜底处理者&rdquo;。<br />当一个异常发生时,Windows 内部顺序是:<br />``1️⃣ Vectored Exception Handlers (VEH)<br />&darr;<br />2️⃣ 线程的 SEH (__try / __except)<br />&darr;<br />3️⃣ C++ try / catch<br />&darr;<br />4️⃣ UnhandledExceptionFilter (UEF)<br />&darr;<br />5️⃣ Windows 默认异常处理(弹框 / 进程终止)`</p></blockquote>
<table><thead><tr><th>对比项</th><th>VEH</th><th>UEF</th></tr></thead><tbody><tr><td>调用时机</td><td><strong>最早</strong></td><td><strong>最后</strong></td></tr><tr><td>是否能看到 first-chance</td><td>✅ 能</td><td>❌ 不能</td></tr><tr><td>是否会被覆盖</td><td>❌ 不会</td><td>✅ 经常</td></tr><tr><td>稳定性</td><td>⭐⭐⭐⭐⭐</td><td>⭐⭐</td></tr><tr><td>使用难度</td><td>高</td><td>低</td></tr><tr><td>线上推荐</td><td>✅</td><td>❌</td></tr></tbody></table>
<p class="maodian"></p><h2>三、可直接复用的代码:</h2>
<p>CrashDump.h:</p>
<div class="jb51code"><pre class="brush:cpp;">#pragma once
#include &lt;Windows.h&gt;

class CrashDump
{
public:
    static void Install();

private:
    static LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ep);
    static void WriteDump(PEXCEPTION_POINTERS ep);

private:
    static volatile LONG s_dumped;
};

</pre></div>
<p>CrashDump.cpp</p>
<div class="jb51code"><pre class="brush:cpp;">#include "CrashDump.h"
#include &lt;DbgHelp.h&gt;
#include &lt;strsafe.h&gt;

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

volatile LONG CrashDump::s_dumped = 0;

void CrashDump::Install()
{
    AddVectoredExceptionHandler(1, VectoredHandler);
}

static bool IsFatalException(DWORD code, DWORD flags)
{
    // 明确忽略的异常(正常流程)
    switch (code)
    {
    case EXCEPTION_BREAKPOINT:
    case EXCEPTION_SINGLE_STEP:
    case 0xE06D7363: // C++ Exception
      return false;
    default:
      break;
    }

    // 不可继续异常 → 一定是致命的
    if (flags &amp; EXCEPTION_NONCONTINUABLE)
      return true;

    // 常见致命异常
    switch (code)
    {
    case EXCEPTION_ACCESS_VIOLATION:
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
    case EXCEPTION_DATATYPE_MISALIGNMENT:
    case EXCEPTION_ILLEGAL_INSTRUCTION:
    case EXCEPTION_IN_PAGE_ERROR:
    case EXCEPTION_STACK_OVERFLOW:
      return true;
    default:
      return false;
    }
}

LONG CALLBACK CrashDump::VectoredHandler(PEXCEPTION_POINTERS ep)
{
    if (!ep || !ep-&gt;ExceptionRecord)
      return EXCEPTION_CONTINUE_SEARCH;

    DWORD code = ep-&gt;ExceptionRecord-&gt;ExceptionCode;
    DWORD flags = ep-&gt;ExceptionRecord-&gt;ExceptionFlags;

    // ⭐ 只处理真正致命异常
    if (!IsFatalException(code, flags))
      return EXCEPTION_CONTINUE_SEARCH;

    if (InterlockedCompareExchange(&amp;s_dumped, 1, 0) == 0)
    {
      WriteDump(ep);

      // ❗真正崩溃点,立即终止
      TerminateProcess(GetCurrentProcess(), code);
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

void CrashDump::WriteDump(PEXCEPTION_POINTERS ep)
{
    wchar_t dir = { 0 };
    GetModuleFileNameW(nullptr, dir, MAX_PATH);

    wchar_t* slash = wcsrchr(dir, L'\\');
    if (slash) *slash = 0;

    SYSTEMTIME st;
    GetLocalTime(&amp;st);

    DWORD pid = GetCurrentProcessId();
    DWORD tid = GetCurrentThreadId();

    wchar_t path = { 0 };

    StringCchPrintfW(
      path,
      MAX_PATH,
      L"%s\\DumpFile-%04d%02d%02d-%02d%02d%02d-P%u-T%u.dmp",
      dir,
      st.wYear, st.wMonth, st.wDay,
      st.wHour, st.wMinute, st.wSecond,
      pid, tid);

    HANDLE hFile = CreateFileW(
      path,
      GENERIC_WRITE,
      0,
      nullptr,
      CREATE_ALWAYS,
      FILE_ATTRIBUTE_NORMAL,
      nullptr);

    if (hFile == INVALID_HANDLE_VALUE)
      return;

    MINIDUMP_EXCEPTION_INFORMATION mei = {};
    mei.ThreadId = tid;
    mei.ExceptionPointers = ep;
    mei.ClientPointers = FALSE;

    MINIDUMP_TYPE type = (MINIDUMP_TYPE)(
      MiniDumpWithFullMemory |
      MiniDumpWithThreadInfo |
      MiniDumpWithHandleData |
      MiniDumpWithUnloadedModules);

    MiniDumpWriteDump(
      GetCurrentProcess(),
      pid,
      hFile,
      type,
      &amp;mei,
      nullptr,
      nullptr);

    CloseHandle(hFile);
}

</pre></div>
<p>在main函数中调用:</p>
<div class="jb51code"><pre class="brush:cpp;"> CrashDump::Install();

QApplication a(argc, argv);
...
</pre></div>
<p class="maodian"></p><h2>四、调试:</h2>
<p>1、将dump文件放在对应的exe、pdb文件同级目录下;</p>
<p>2、</p>
<p>1)使用Visual Studio打开dump文件,然后设置符号路径,路径下需要有exe、pdb、dump;</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011109102625.png" /></p>
<p>2)点击&ldquo;使用仅限本机进行调试&rdquo;,即可重新异常情况;</p>
<p class="maodian"></p><h2>总结</h2>
<p>到此这篇关于vs2019+qt工程中如何生成dump文件及调试的文章就介绍到这了,更多相关vs2019&nbsp;qt生成dump文件及调试内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: vs2019+qt工程中如何生成dump文件及调试详解