### 如何在VS2010中配置程序以在崩溃时自动创建DUMP文件
本文档将详细介绍如何在Visual Studio 2010 (VS2010)中配置一个项目,使其能够在程序崩溃时自动生成DUMP文件,并提供一些基本的DUMP文件分析方法。
#### 一、基础知识介绍
在开始之前,我们先了解一些基本概念:
- **DUMP文件**:一种用于记录程序崩溃时状态的文件,通常包含线程上下文、内存状态等关键信息。
- **Visual Studio 2010 (VS2010)**:一款由微软开发的集成开发环境(IDE),广泛用于Windows平台的应用开发。
- **DbgHelp库**:提供了用于创建、解析和处理DUMP文件的API,是实现本功能的核心组件之一。
- **Windbg**:微软提供的调试工具,可用于分析DUMP文件,找出导致程序崩溃的原因。
#### 二、准备工作
在开始编写代码之前,请确保已经安装了以下组件:
- Visual Studio 2010
- Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1
- Debugging Tools for Windows (x86)
#### 三、实现步骤
##### 1. 配置项目
在VS2010中打开或创建一个新的项目,然后进行如下设置:
- 打开项目的属性页面(`右击项目名称 -> 属性`)。
- 在配置属性中选择C/C++ -> 常规 -> 添加附加包含目录(`C:\Program Files (x86)\Windows Kits\8.0\Include\ucrt` 和 `C:\Program Files (x86)\Windows Kits\8.0\Include\shared`)。
- 连接器 -> 常规 -> 添加附加库目录(`C:\Program Files (x86)\Windows Kits\8.0\Lib\ucrt\x86` 和 `C:\Program Files (x86)\Windows Kits\8.0\Lib\shared\x86`)。
- 连接器 -> 输入 -> 添加附加依赖项(`dbghelp.lib`)。
##### 2. 编写代码
接下来,我们需要编写一段代码来实现DUMP文件的自动创建。示例代码如下:
```cpp
#include
#include
#include
#pragma comment(lib, "dbghelp.lib")
// 判断是否需要保留数据段
inline BOOL IsDataSectionNeeded(const WCHAR *pModuleName)
{
if (pModuleName == 0)
return FALSE;
WCHAR szFileName[_MAX_FNAME] = L"";
_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
if (_wcsicmp(szFileName, L"ntdll") == 0)
return TRUE;
return FALSE;
}
// DUMP文件回调函数
inline BOOL CALLBACK MiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput)
{
if (pInput == 0 || pOutput == 0)
return FALSE;
switch (pInput->CallbackType)
{
case ModuleCallback:
if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
if (!IsDataSectionNeeded(pInput->Module.FullPath))
pOutput->ModuleWriteFlags &= ~(ModuleWriteDataSeg);
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
default:
break;
}
return FALSE;
}
// 创建Mini Dump
inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)
{
HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = NULL;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
mci.CallbackParam = 0;
::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);
CloseHandle(hFile);
}
}
// 异常过滤器
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
CreateMiniDump(pExceptionInfo, L"core.dmp");
return EXCEPTION_EXECUTE_HANDLER;
}
// 禁止调用SetUnhandledExceptionFilter
void DisableSetUnhandledExceptionFilter()
{
void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"), "SetUnhandledExceptionFilter");
if (addr)
{
unsigned char code[16];
int size = 0;
code[size++] = 0x33;
code[size++] = 0xC0;
code[size++] = 0xC2;
code[size++] = 0x04;
code[size++] = 0x00;
DWORD oldProtect = 0;
// 代码注入逻辑省略...
}
}
```
这段代码实现了以下功能:
- `IsDataSectionNeeded`: 判断模块名是否为“ntdll”,如果是,则返回`TRUE`,表示该模块的数据段需要被保留。
- `MiniDumpCallback`: 回调函数,用于控制哪些模块的数据段需要被包含在DUMP文件中。
- `CreateMiniDump`: 核心函数,当程序崩溃时会调用该函数创建DUMP文件。
- `MyUnhandledExceptionFilter`: 当未处理异常发生时,系统会调用这个函数来处理异常。这里创建DUMP文件后返回`EXCEPTION_EXECUTE_HANDLER`,以便程序继续执行。
##### 3. 注册异常处理器
最后一步是在程序启动时注册异常处理器,可以使用以下代码:
```cpp
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
```
这行代码需要放在程序的入口函数(如`main()`)中,确保程序在启动时就注册了自定义的异常处理函数。
#### 四、分析DUMP文件
一旦生成了DUMP文件,我们可以使用Windbg来分析它。以下是一些基本命令:
- `.loadby sos mscorwks`:加载.NET框架调试支持。
- `!analyze -v`:分析DUMP文件中的异常情况。
- `kb`:显示调用堆栈。
- `lm`:列出所有已加载的模块。
通过这些命令,你可以获取到崩溃时的详细信息,从而定位问题并修复它。
#### 五、总结
通过以上步骤,你可以在Visual Studio 2010中轻松地为项目配置异常处理机制,使其能够在崩溃时自动生成DUMP文件。这些DUMP文件随后可以通过Windbg等工具进行分析,帮助开发者快速定位问题所在。这种方式不仅适用于开发阶段,也可以应用于生产环境,提高应用的稳定性和用户体验。
1