今月はまだ面白いことを書けていなくてすみません、とても忙しい月でした。
今日、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ファイルを保管してください。そうでなければ、簡単に読める情報が得られません。
それではまた! 😉
コメント