参考: http://blog.csdn.net/ArCoolGG/archive/2007/04/05/1553027.aspx
首先,写一个 异常处理函数。
std::ostream& operator << ( std::ostream& os, const EXCEPTION_RECORD& red )
{ //
return os << " Thread ID:" << GetCurrentThreadId()
<< " ExceptionCode: " << red.ExceptionCode << "\n"
<< " ExceptionFlags: " << red.ExceptionFlags << "\n"
<< " ExceptionAddress: " << red.ExceptionAddress << "\n"
<< " NumberParameters: " << red.NumberParameters;
}
// 这个处理函数调用 Nick 的 minidump 创建 dmp 文件。
#include "minidump.h"
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
CreateMiniDump( pExceptionInfo, "myproject.dmp" );
std::cerr << " 未知错误: " << (*pExceptionInfo->ExceptionRecord ) << std::endl;
exit( pExceptionInfo->ExceptionRecord->ExceptionCode );
return EXCEPTION_EXECUTE_HANDLER;
}
然后在 main 函数开始的时候(只要在异常发生之前)调用 api
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
把 未捕获的异常(主要应该是飞指针造成的) 传送给 我们的 MyUnhandledExceptionFilter 函数来处理, 而不是由操作系统弹出那个让人不知所云的非法错误提示窗口。
这些代码会帮助你创建一个 dmp 文件,把这个文件和编译时产生的 exe, pdb 文件放在一起,然后使用 vs 2005 或者 dmp 处理工具打开,就可以直接定位到错误发生时执行的代码,还包括堆栈和有限的变量信息(别相信 this 是0,this 在dmp中永远显示0)。
注意:exe 必须能找到 dbghelp.dll 才能正确生成 dmp 文件,这个 dll 你可以从微软的 dbghelp.dll Debugging Tools for Windows 工具中找到,dbghelp.lib 在 vs 2005 中有,否则你可以去 Windows SDK 中找。
当异常代码定位成功以后,如果无法阻止异常的产生,可以用 __try 结构包装异常代码,__try 和 try 不同,前者可以捕获非法指针产生的异常。
__try{
// 会异常的函数
} __except( EXCEPTION_EXECUTE_HANDLER ){
// 异常处理
}
附 minidmp.h
/* Nico 07-4-5 1027
quoted from minidump.cpp@debuginfo.com
*/
#pragma once
#include <windows.h>
#include <imagehlp.h>
#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;
}
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);
// fall through
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
default:;
}
return FALSE;
}
inline void CreateMiniDump( EXCEPTION_POINTERS* pep, LPCSTR filename)
{
HANDLE hFile = CreateFile( filename, GENERIC_READ | GENERIC_WRITE,
0, 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 = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
0x00000800 /*MiniDumpWithFullMemoryInfo*/ |
0x00001000 /*MiniDumpWithThreadInfo*/ |
MiniDumpWithUnloadedModules );
MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci );
CloseHandle( hFile );
}
}