李sir_Blog

博客园 首页 联系 订阅 管理

参考: 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 ); 
 }
}


posted on 2011-03-28 17:09  李sir  阅读(1727)  评论(0编辑  收藏  举报