记录程序崩溃时的调用堆栈
在程序release之后,不可避免的会存在一些bug,测试人员和最终用户如何在发现bug之后指导开发人员进行更正呢?在MS的网站上,有一篇名为"Under the hook"的文章,讲述了如何把程序崩溃时的函数调用情况记录为日志的方法,对此感兴趣的读者可以去看一看原文,那里提供源代码和原理的说明。
文章的作者提供了一个MSJExceptionHandler类来实现这一功能,这个类的使用方法很简单,只要把这个类加入到你的工程中并和你的程序一起编译就可以了,由于在这个类的实现文件中把自己定义为一个全局的类对象,所以,不用加入任何代码,#include都不需要。
当程序崩溃时,MSJExceptionHandler就会把崩溃时的堆栈调用情况记录在一个.rpt文件中,软件的测试人员或最终用户只要把这个文件发给你,而你使用记事本打开这个文件就可以查看崩溃原因了。你需要在发行软件的时候,为你的程序生成一个或几个map文件,用于定位出错的文件和函数。(我的另一篇blog中有关于生成map文件和定位错误的详细说明)为了方便使用,这里附上该类的完整代码:
// msjexhnd.h
#ifndef __MSJEXHND_H__
#define __MSJEXHND_H__
class MSJExceptionHandler
{
public:
MSJExceptionHandler( );
~MSJExceptionHandler( );
void SetLogFileName( PTSTR pszLogFileName );
private:
// entry point where control comes on an unhandled exception
static LONG WINAPI MSJUnhandledExceptionFilter(
PEXCEPTION_POINTERS pExceptionInfo );
// where report info is extracted and generated
static void GenerateExceptionReport( PEXCEPTION_POINTERS pExceptionInfo );
// Helper functions
static LPTSTR GetExceptionString( DWORD dwCode );
static BOOL GetLogicalAddress( PVOID addr, PTSTR szModule, DWORD len,
DWORD& section, DWORD& offset );
static void IntelStackWalk( PCONTEXT pContext );
static int __cdecl _tprintf(const TCHAR * format, ...);
// Variables used by the class
static TCHAR m_szLogFileName[MAX_PATH];
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
static HANDLE m_hReportFile;
};
extern MSJExceptionHandler g_MSJExceptionHandler; // global instance of class
#endif
// msjexhnd.cpp
//==========================================
// Matt Pietrek
// Microsoft Systems Journal, April 1997
// FILE: MSJEXHND.CPP
//==========================================
#include <windows.h>
#include <tchar.h>
#include "msjexhnd.h"
//============================== Global Variables =============================
//
// Declare the static variables of the MSJExceptionHandler class
//
TCHAR MSJExceptionHandler::m_szLogFileName[MAX_PATH];
LPTOP_LEVEL_EXCEPTION_FILTER MSJExceptionHandler::m_previousFilter;
HANDLE MSJExceptionHandler::m_hReportFile;
MSJExceptionHandler g_MSJExceptionHandler; // Declare global instance of class
//=====================