以前写的一个例子, 现在才放上来..
程序出错时, 调用BugSlayerUtil.dll 中的函数将调用栈(callstack) 写入文件. 用来调试程序, 事半功倍.
首先要做的是让程序带有调试信息. 以 vc6 IDE 为例. 打开项目属性, 切换到所有配置(All Configurations), 然后C/C++属性页下的 General 类, 将 Debug info 改成 Program Database.
然后切换到 Link 页, 选择 Debug 类,选中 Debug Info, 并选中 Microsoft format.
将附带的 include 目录复制到你的硬盘中, 比如d:/include, 在如图的 Directories 中指定这个目录.
最简单的做法就是包含UnhandledExceptionFilter.h, 然后把其中的CUnhandledExceptionFilter 类作为 app 类的父类. 就像附带的 TestBugslayer 项目一样. 类 CUnhandledExceptionFilter 会在构造的时候调用SetUnhandledExceptionFilter(). 如果你有自己的 UnhandledExceptionFilter 函数, 则不要从CUnhandledExceptionFilter 派生. 可以在自己的UnhandledExceptionFilter 函数中调用CUnhandledExceptionFilter::GetCrashInfoString() 静态函数, 该函数将返回包括调用栈在内的丰富调试信息的一个字符串. 你需要做的只是把这个字符串写入文件即可.
当然, 你的程序能通过编译连接还需要BugslayerUtil.lib 文件. 你可以简单的将这个文件复制到你的源文件目录中. 另外, 要运行你的程序需要BugslayerUtil.dll 文件. 确保它在你的项目生成 exe 的目录中.
注意: 由于 release 版本中用到的系统 dll 不带调试信息, release 版本的程序导出的调用栈信息会较 debug 版程序少一些. 但关键的出错行还是会有的. 另外, 发布程序时需要带上编译时生成 pdb 文件
附录:
Appendix:
Where does BugslayerUtil.dll come from?
BugslayerUtil.dll 来自 John Robbins 的 Bugslayer专栏. John 将每次专栏中写的工具都放到了BugslayerUtil.dll.
http://www.microsoft.com/msj/0898/bugslayer0898.aspx
调用栈的信息如下形式:
DEBUG 版程序:
RnmsAdaptorD.exe caused a EXCEPTION_ACCESS_VIOLATION in module MSVCRTD.dll at 001B:10218207, memset()+71 byte(s), intel/memset.asm, line 115
EAX=00000000 EBX=000504E2 ECX=00000000 EDX=00000001 ESI=5F4335C0
EDI=00000000 EBP=0013EF04 ESP=0013EEC4 EIP=10218207 FLG=00010293
CS=001B DS=0023 SS=0023 ES=0023 FS=003B GS=0000
001B:10218207 (0x00000000 0x00000000 0x00000001 0x5F4335C0) MSVCRTD.dll, memset()+71 byte(s), intel/memset.asm, line 115
001B:00410383 (0x0013F624 0x0013EF3C 0x77D48734 0x00060434) RnmsAdaptorD.exe, CAboutDlg::OnInitDialog()+76 byte(s), D:/mss3000/v220/RnmsAdaptor/RnmsAdaptorDlg.cpp, line 546+11 byte(s)
001B:5F4335FB (0x00060434 0x00000110 0x000504E2 0x00000000) MFC42D.DLL, AfxDlgProc()+59 byte(s), dlgcore.cpp, line 35+14 byte(s)
001B:77D48734 (0x5F4335C0 0x00060434 0x00000110 0x000504E2) USER32.dll, GetDC()+109 byte(s)
001B:77D545E4 (0x00000000 0x5F4335C0 0x00060434 0x00000110) USER32.dll, DefDlgProcW()+1026 byte(s)
001B:77D53FD9 (0x00000000 0x00000110 0x000504E2 0x00000000) USER32.dll, PrivateExtractIconExW()+254 byte(s)
001B:77D6E571 (0x00060434 0x00000110 0x000504E2 0x00000000) USER32.dll, DefDlgProcA()+34 byte(s)
001B:77D48734 (0x77D6E54F 0x00060434 0x00000110 0x000504E2) USER32.dll, GetDC()+109 byte(s)
001B:77D48816 (0x00000000 0x77D6E54F 0x00060434 0x00000110) USER32.dll, GetDC()+335 byte(s)
001B:77D4C63F (0x77D6E54F 0x00060434 0x00000110 0x000504E2) USER32.dll, IsWindowUnicode()+161 byte(s)
001B:77D4E905 (0x77D6E54F 0x00060434 0x00000110 0x000504E2) USER32.dll, CallWindowProcA()+27 byte(s)
001B:5F42DF36 (0x00000110 0x000504E2 0x00000000 0x0013F624) MFC42D.DLL, CWnd::DefWindowProcA()+50 byte(s), wincore.cpp, line 1000+32 byte(s)
001B:5F42C8CB (0x0013F624 0x5F495541 0x5F4CFE48 0x00000000) MFC42D.DLL, CWnd::Default()+57 byte(s), wincore.cpp, line 249
001B:5F434816 (0x000504E2 0x00000000 0x0013F2CC 0x00155060) MFC42D.DLL, CDialog::HandleInitDialog()+173 byte(s), dlgcore.cpp, line 621+8 byte(s)
001B:5F42F2AC (0x00000110 0x000504E2 0x00000000 0x0013F268) MFC42D.DLL, CWnd::OnWndMsg()+1690 byte(s), wincore.cpp, line 1815+17 byte(s)
001B:5F42EBE8 (0x00000110 0x000504E2 0x00000000 0x0013F3A4) MFC42D.DLL, CWnd::WindowProc()+46 byte(s), wincore.cpp, line 1585+30 byte(s)
001B:5F42C789 (0x0013F624 0x00060434 0x00000110 0x000504E2) MFC42D.DLL, AfxCallWndProc()+237 byte(s), wincore.cpp, line 215+26 byte(s)
001B:5F42CC25 (0x00060434 0x00000110 0x000504E2 0x00000000) MFC42D.DLL, AfxWndProc()+129 byte(s), wincore.cpp, line 368
001B:5F49049D (0x00060434 0x00000110 0x000504E2 0x00000000) MFC42D.DLL, AfxWndProcBase()+74 byte(s), afxstate.cpp, line 220+21 byte(s)
001B:77D48734 (0x5F490453 0x00060434 0x00000110 0x000504E2) USER32.dll, GetDC()+109 byte(s)
001B:77D48816 (0x00000000 0x5F490453 0x00060434 0x00000110) USER32.dll, GetDC()+335 byte(s)
001B:77D4B89B (0x00691700 0x0068B778 0x000504E2 0x00000000) USER32.dll, GetParent()+364 byte(s)
001B:77D54E28 (0x00000000 0x00691700 0x00000194 0x00060434) USER32.dll, GetWindowTextLengthW()+1351 byte(s)
001B:77D5514C (0x00400000 0x00428278 0x000A0422 0x5F4335C0) USER32.dll, CreateDialogIndirectParamAorW()+51 byte(s)
001B:77D69B1B (0x00400000 0x00428278 0x000A0422 0x5F4335C0) USER32.dll, CreateDialogIndirectParamA()+27 byte(s)
001B:5F433F17 (0x00428278 0x0013FBA4 0x00400000 0x0013F684) MFC42D.DLL, CWnd::CreateDlgIndirect()+662 byte(s), dlgcore.cpp, line 327+36 byte(s)
001B:5F434552 (0x0013F930 0x0013FBA4 0x0041D684 0x00000001) MFC42D.DLL, CDialog::DoModal()+324 byte(s), dlgcore.cpp, line 528+32 byte(s)
001B:0040FF5A (0x0013F930 0x00155060 0x00000000 0x0000000A) RnmsAdaptorD.exe, CRnmsAdaptorDlg::OnHelpAbout()+71 byte(s), D:/mss3000/v220/RnmsAdaptor/RnmsAdaptorDlg.cpp, line 428
001B:5F4373FC (0x0013FBA4 0x00008004 0x00000000 0x00401311) MFC42D.DLL, _AfxDispatchCmdMsg()+162 byte(s), cmdtarg.cpp, line 88
001B:5F437B2B (0x00008004 0x00000000 0x00000000 0x00000000) MFC42D.DLL, CCmdTarget::OnCmdMsg()+628 byte(s), cmdtarg.cpp, line 302+39 byte(s)
001B:5F43374B (0x00008004 0x00000000 0x00000000 0x00000000) MFC42D.DLL, CDialog::OnCmdMsg()+36 byte(s), dlgcore.cpp, line 97+24 byte(s)
001B:5F42FA63 (0x00008004 0x00000000 0x0013F930 0x00155060) MFC42D.DLL, CWnd::OnCommand()+312 byte(s), wincore.cpp, line 2088
001B:5F42EC65 (0x00000111 0x00008004 0x00000000 0x0013F8CC) MFC42D.DLL, CWnd::OnWndMsg()+83 byte(s), wincore.cpp, line 1597+28 byte(s)
001B:5F42EBE8 (0x00000111 0x00008004 0x00000000 0x0013FA08) MFC42D.DLL, CWnd::WindowProc()+46 byte(s), wincore.cpp, line 1585+30 byte(s)
001B:5F42C789 (0x0013FBA4 0x000A0422 0x00000111 0x00008004) MFC42D.DLL, AfxCallWndProc()+237 byte(s), wincore.cpp, line 215+26 byte(s)
001B:5F42CC25 (0x000A0422 0x00000111 0x00008004 0x00000000) MFC42D.DLL, AfxWndProc()+129 byte(s), wincore.cpp, line 368
001B:5F49049D (0x000A0422 0x00000111 0x00008004 0x00000000) MFC42D.DLL, AfxWndProcBase()+74 byte(s), afxstate.cpp, line 220+21 byte(s)
001B:77D48734 (0x5F490453 0x000A0422 0x00000111 0x00008004) USER32.dll, GetDC()+109 byte(s)
001B:77D48816 (0x00000000 0x5F490453 0x000A0422 0x00000111) USER32.dll, GetDC()+335 byte(s)
001B:77D489CD (0x00424A68 0x00000001 0x0013FAC0 0x5F4396C8) USER32.dll, GetWindowLongW()+295 byte(s)
001B:77D496C7 (0x00424A68 0x0013FEDC 0x0013FB64 0x7FFDE000) USER32.dll, DispatchMessageA()+15 byte(s)
001B:5F4396C8 (0x0013FEDC 0x0013FB64 0x7FFDE000 0x00424A30) MFC42D.DLL, CWinThread::PumpMessage()+256 byte(s), thrdcore.cpp, line 846
001B:5F43219F (0x00000004 0x0013FEDC 0x0013FB64 0x7FFDE000) MFC42D.DLL, CWnd::RunModalLoop()+514 byte(s), wincore.cpp, line 3478+19 byte(s)
001B:5F43459F (0x7C903804 0x0013E3EC 0x0013FB90 0x0013FB90) MFC42D.DLL, CDialog::DoModal()+401 byte(s), dlgcore.cpp, line 536+12 byte(s)
001B:00403FC4 (0x7C903804 0x0013E3EC 0x7FFDE000 0x00424A30) RnmsAdaptorD.exe, CRnmsAdaptorApp::InitInstance()+1038 byte(s), D:/mss3000/v220/RnmsAdaptor/RnmsAdaptor.cpp, line 205+11 byte(s)
001B:5F433523 (0x00400000 0x00000000 0x001523A1 0x00000001) MFC42D.DLL, AfxWinMain()+131 byte(s), winmain.cpp, line 39+11 byte(s)
001B:00418AF8 (0x00400000 0x00000000 0x001523A1 0x00000001) RnmsAdaptorD.exe, WinMain()+24 byte(s), appmodul.cpp, line 30
001B:00418513 (0x7C903804 0x0013E3EC 0x7FFDE000 0x8054A6ED) RnmsAdaptorD.exe, WinMainCRTStartup()+435 byte(s), crtexe.c, line 330+54 byte(s)
001B:7C816FD7 (0x00418360 0x00000000 0x78746341 0x00000020) kernel32.dll, RegisterWaitForInputIdle()+73 byte(s)
RELEASE 版程序:
RnmsAdaptor.exe caused a EXCEPTION_ACCESS_VIOLATION in module RnmsAdaptor.exe at 001B:00407C74, CAboutDlg::OnInitDialog()+36 byte(s), D:/mss3000/v220/RnmsAdaptor/RnmsAdaptorDlg.cpp, line 546+2 byte(s)
EAX=00000000 EBX=0013F7CC ECX=00000000 EDX=7FFEFFFF ESI=73DD6745
EDI=00000000 EBP=0013F20C ESP=0013F1BC EIP=00407C74 FLG=00010246
CS=001B DS=0023 SS=0023 ES=0023 FS=003B GS=0000
001B:00407C74 (0x77D48734 0x0011045C 0x00000110 0x002E04FC) RnmsAdaptor.exe, CAboutDlg::OnInitDialog()+36 byte(s), D:/mss3000/v220/RnmsAdaptor/RnmsAdaptorDlg.cpp, line 546+2 byte(s)
001B:73DD6773 (0x73DD6745 0x0011045C 0x00000110 0x002E04FC) MFC42.DLL, Ordinal1130()+46 byte(s)
001B:77D545E4 (0x00000000 0x73DD6745 0x0011045C 0x00000110) USER32.dll, DefDlgProcW()+1026 byte(s)
001B:77D53FD9 (0x00000000 0x00000110 0x002E04FC 0x00000000) USER32.dll, PrivateExtractIconExW()+254 byte(s)
001B:77D6E571 (0x0011045C 0x00000110 0x002E04FC 0x00000000) USER32.dll, DefDlgProcA()+34 byte(s)
001B:77D48734 (0x77D6E54F 0x0011045C 0x00000110 0x002E04FC) USER32.dll, GetDC()+109 byte(s)
001B:77D48816 (0x00000000 0x77D6E54F 0x0011045C 0x00000110) USER32.dll, GetDC()+335 byte(s)
001B:77D4C63F (0x77D6E54F 0x0011045C 0x00000110 0x002E04FC) USER32.dll, IsWindowUnicode()+161 byte(s)
001B:77D4E905 (0x77D6E54F 0x0011045C 0x00000110 0x002E04FC) USER32.dll, CallWindowProcA()+27 byte(s)
001B:73DD216B (0x00000110 0x002E04FC 0x00000000 0x0013F7CC) MFC42.DLL, Ordinal2385()+68 byte(s)
001B:73DD21EC (0x00000110 0x002E04FC 0x73E7B0E8 0x0013F49C) MFC42.DLL, Ordinal2379()+39 byte(s)
001B:73DD1B9B (0x00000110 0x002E04FC 0x00000000 0x0013F5B4) MFC42.DLL, Ordinal6374()+36 byte(s)
001B:73DD1B05 (0x0013F7CC 0x84C800C4 0x00000110 0x002E04FC) MFC42.DLL, Ordinal1109()+145 byte(s)
001B:73DD1A58 (0x0011045C 0x00000110 0x002E04FC 0x00000000) MFC42.DLL, Ordinal1578()+54 byte(s)
001B:73E6847D (0x0011045C 0x00000110 0x002E04FC 0x00000000) MFC42.DLL, Ordinal1579()+57 byte(s)
001B:77D48734 (0x73E68444 0x0011045C 0x00000110 0x002E04FC) USER32.dll, GetDC()+109 byte(s)
001B:77D48816 (0x00000000 0x73E68444 0x0011045C 0x00000110) USER32.dll, GetDC()+335 byte(s)
001B:77D4B89B (0x0062CC10 0x00629BF0 0x002E04FC 0x00000000) USER32.dll, GetParent()+364 byte(s)
001B:77D54E28 (0x00000000 0x0062CC10 0x00000194 0x0011045C) USER32.dll, GetWindowTextLengthW()+1351 byte(s)
001B:77D5514C (0x00400000 0x004140E8 0x0029054A 0x73DD6745) USER32.dll, CreateDialogIndirectParamAorW()+51 byte(s)
001B:77D69B1B (0x00400000 0x004140E8 0x0029054A 0x73DD6745) USER32.dll, CreateDialogIndirectParamA()+27 byte(s)
001B:73DDF11E (0x004140E8 0x0013FBDC 0x00400000 0x0013FBDC) MFC42.DLL, Ordinal2147()+373 byte(s)
001B:73DE6A08 (0x0040D9C0 0x00000001 0x00000000 0x00000000) MFC42.DLL, Ordinal2514()+194 byte(s)
001B:004078B2 (0x0040D7C0 0x00000111 0x0013F874 0x73DD23BF) RnmsAdaptor.exe, CRnmsAdaptorDlg::OnHelpAbout()+50 byte(s), D:/mss3000/v220/RnmsAdaptor/RnmsAdaptorDlg.cpp, line 428
001B:73DD24C0 (0x0013FBDC 0x00008004 0x00000000 0x00407880) MFC42.DLL, Ordinal567()+171 byte(s)
001B:73DD23BF (0x00008004 0x00000000 0x00000000 0x00000000) MFC42.DLL, Ordinal4424()+266 byte(s)
001B:73E3DEAD (0x00008004 0x00000000 0x00000000 0x00000000) MFC42.DLL, Ordinal4431()+29 byte(s)
001B:73DD3244 (0x00000000 0x00000000 0x0013FBDC 0x0013FBDC) MFC42.DLL, Ordinal4441()+83 byte(s)
001B:73DD1BF1 (0x00000111 0x00008004 0x00000000 0x0013F984) MFC42.DLL, Ordinal5163()+47 byte(s)
001B:73DD1B9B (0x00000111 0x00008004 0x00000000 0x0013FA9C) MFC42.DLL, Ordinal6374()+36 byte(s)
001B:73DD1B05 (0x0013FBDC 0x00000000 0x00000111 0x00008004) MFC42.DLL, Ordinal1109()+145 byte(s)
001B:73DD1A58 (0x0029054A 0x00000111 0x00008004 0x00000000) MFC42.DLL, Ordinal1578()+54 byte(s)
001B:73E6847D (0x0029054A 0x00000111 0x00008004 0x00000000) MFC42.DLL, Ordinal1579()+57 byte(s)
001B:77D48734 (0x73E68444 0x0029054A 0x00000111 0x00008004) USER32.dll, GetDC()+109 byte(s)
001B:77D48816 (0x00000000 0x73E68444 0x0029054A 0x00000111) USER32.dll, GetDC()+335 byte(s)
001B:77D489CD (0x00412844 0x00000001 0x00412844 0x73DD125A) USER32.dll, GetWindowLongW()+295 byte(s)
001B:77D496C7 (0x00412844 0x00000000 0x0013FBDC 0x73DE6B99) USER32.dll, DispatchMessageA()+15 byte(s)
001B:73DD125A (0x00008004 0x00000000 0x009068FE 0x0000014D) MFC42.DLL, Ordinal5307()+60 byte(s)
googlepages 最近不能用. 找个 ftp 先放上代码和带插图的 doc 版本