이번 달에 아직 흥미로운 글을 쓰지 못해서 죄송합니다. 매우 바쁜 달이었습니다.

오늘 Stack Overflow 에서 디버깅에 관한 질문을 보았습니다. 사용자가 Visual Studio를 디버그 모드로 실행하여 애플리케이션이 언제 왜 충돌하는지 확인하려고 했습니다.

이것은 해결책이 아닙니다. Windows API에는 이러한 상황을 위한 기능이 있기 때문입니다. 간단히 말해, 소프트웨어가 충돌할 때 Mini Dump를 작성하도록 설정한 다음, Visual Studio(또는 원하는 디버거)에서 열어 정확히 어디에서 충돌이 발생했는지 확인할 수 있습니다.

다음 예제는 Windows의 모든 .exe 또는 .dll에서 바로 사용할 수 있습니다:

 1#pragma once
 2
 3#include <Windows.h>
 4#include <Dbghelp.h>
 5#pragma comment (lib, "Dbghelp.lib")
 6
 7// Because... why not ?!
 8namespace MecanikUtils
 9{
10LPTOP_LEVEL_EXCEPTION_FILTER PreviousExceptionFilter = 0;
11
12    LONG WINAPI DumpExceptionFilter(EXCEPTION_POINTERS* info)
13    {
14        wchar_t DumpPath[MAX_PATH] = { 0 };
15
16        SYSTEMTIME SystemTime;
17        GetLocalTime(&SystemTime);
18
19        WCHAR szExeFileName[100] = { 0 };
20        GetModuleFileNameW(NULL, szExeFileName, 99);
21
22        wsprintfW(DumpPath, L"Crash_%s_%d-%d-%d_%dh%dm%ds.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);
23
24        HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
25
26        if (file != INVALID_HANDLE_VALUE)
27        {
28            MINIDUMP_EXCEPTION_INFORMATION mdei;
29
30            mdei.ThreadId = (DWORD)GetCurrentThreadId();
31
32            mdei.ExceptionPointers = info;
33
34            mdei.ClientPointers = 0;
35
36            if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD)GetCurrentProcessId(), file, (MINIDUMP_TYPE)(MiniDumpScanMemory + MiniDumpWithIndirectlyReferencedMemory), &mdei, 0, 0) != 0)
37            {
38                CloseHandle(file);
39                return EXCEPTION_EXECUTE_HANDLER;
40            }
41        }
42
43        CloseHandle(file);
44
45        return EXCEPTION_CONTINUE_SEARCH;
46    }
47
48    class MiniDump
49    {
50    public:
51
52        /// <summary>
53        /// Add Unhandled Exception Filter
54        /// </summary>
55        inline static void Init()
56        {
57            // Change if required
58            SetErrorMode(SEM_FAILCRITICALERRORS);
59
60            PreviousExceptionFilter = SetUnhandledExceptionFilter(DumpExceptionFilter);
61        }
62
63        /// <summary>
64        /// Remove Unhandled Exception Filter
65        /// </summary>
66        inline static void Clean()
67        {
68            SetUnhandledExceptionFilter(PreviousExceptionFilter);
69        }
70    };
71
72}

사용하려면 소프트웨어 진입점의 시작과 끝에서 다음을 호출하면 됩니다. 예를 들어 .dll의 경우:

 1#include "MiniDump.hpp"
 2
 3BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
 4{
 5switch ( ul_reason_for_call )
 6{
 7case DLL_PROCESS_ATTACHED:
 8MecanikUtils::MiniDump::Init();
 9break;
10
11      case DLL_PROCESS_DETACH:
12      MecanikUtils::MiniDump::Clean();
13      break;
14
15}
16return TRUE;
17}

필요한 경우 SetErrorMode 를 자유롭게 수정하세요.

참고: Mini Dump를 열려면 컴파일된 .exe/.dll의 원본 .pdb 파일을 보관하세요. 그렇지 않으면 쉽게 읽을 수 있는 정보를 얻을 수 없습니다.

다음에 만나요! 😉