有时候程序在客户那里崩溃了,你程序也没有什么有效的log日志能记录到崩溃的细节,那这实在是一件很麻烦的事情。
你得向客户反复了解操作内容并希望能在自己这里重现,这个过程想想都很痛苦吧。。
使用下面的方法,能在程序崩溃时生成一个自己的dump文件,记录了崩溃时的一些有用的信息,一般能帮你容易地找到出错的地方。
简单地说,就是windows程序崩溃时会调一个对话框显示一些没什么用的信息。
有一个方法可以让我们设置程序崩溃时先执行的回调函数,这里面可以弹我们自己的对话框,比如让用户输入一些有用的内容然后发送给我们。
这个函数是SetUnhandledExceptionFilter .
原型:
WINBASEAPI LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter( __in_opt LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter );它的参数是你要设置的回调函数:PTOP_LEVEL_EXCEPTION_FILTER
typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)( __in struct _EXCEPTION_POINTERS *ExceptionInfo ); typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;
typedef struct _EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord; } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
通过SetUnhandledExceptionFilter 函数的返回值我们可以选择在回调结束后不再弹原来默认的对话框而直接结束程序、或者再弹那个默认的再结束程序、不弹对话框继续执行。
如下:
#define EXCEPTION_EXECUTE_HANDLER 1 //在回调结束后不再弹原来默认的对话框而直接结束程序 #define EXCEPTION_CONTINUE_SEARCH 0 //再弹那个默认的再结束程序 #define EXCEPTION_CONTINUE_EXECUTION -1 //继续执行
往dump文件写内容用到一个API:MiniDumpWriteDump。
在DbgHelp.h头文件中,且需包含 DbgHelp.lib库。
#include <DbgHelp.h> #pragma comment(lib, "dbghelp.lib")
函数形式:
BOOL WINAPI MiniDumpWriteDump( __in HANDLE hProcess, __in DWORD ProcessId, __in HANDLE hFile, __in MINIDUMP_TYPE DumpType, __in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, __in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, __in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam );说明:
hProcess ——进程句柄,使用GetCurrentProcess()获得即可。
ProcessID——进程ID,GetCurrentProcessId()。
hFile ——我们创建的dump文件句柄。
DumpType——dump类型,一般填MiniDumpNormal 即可,具体内容参看DbgHelp.h和MSDN。
ExceptionParam—— 1)ThreadId:GetCurrentThreadId()。
2)ExceptionPointers:即回调函数的参数。
3)ClientPointers:一般填TRUE即可。
UserStreamParam—— 一般设NULL。
CallbackParam —— 一般设NULL。
如果是release版,需要在工程配置中设置生成调试文件和生成映射文件。
如图:
win32控制台程序:
#include "stdafx.h" #include <windows.h> #include <DbgHelp.h> #pragma comment(lib, "dbghelp.lib") //我们的回调函数 LONG __stdcall ExceptCallBack( EXCEPTION_POINTERS *pExcPointer) { MessageBox(NULL,"程序崩溃!相关信息记录在C:\\Test.dmp文件中。",NULL,MB_OK); //创建dump文件 HANDLE hFile = CreateFile("C:\\Test.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL ,NULL); //向文件写下当前程序崩溃相关信息 MINIDUMP_EXCEPTION_INFORMATION loExceptionInfo; loExceptionInfo.ExceptionPointers = pExcPointer; loExceptionInfo.ThreadId = GetCurrentThreadId(); loExceptionInfo.ClientPointers = TRUE; MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),hFile, MiniDumpNormal, &loExceptionInfo, NULL, NULL); CloseHandle(hFile); return EXCEPTION_EXECUTE_HANDLER; } void WrongFun() { //crash int * p = NULL; *p = 1; } int _tmain(int argc, _TCHAR* argv[]) { //设置崩溃回调函数 SetUnhandledExceptionFilter(ExceptCallBack); WrongFun(); return 0; }
crash后先弹出一个对话框:
之后不再调windows自带的崩溃对话框了。程序结束。
用windbg 菜单 File->Open Crash File 打开这个Test.dmp文件,在下方编辑框输入 “!analyze -v” 命令执行自动分析。
稍等一会,就会出现一些内容,大致找到如下:
就能看到程序崩溃的一些细节甚至代码。