[转]window下使用SetUnhandledExceptionFilter捕获让程序的崩溃

简单使用SetUnhandledExceptionFilter()函数让程序优雅崩溃

虽然是大公司的产品,QQ它还是会在我们的折腾下崩溃的,但是它总是崩溃的很优雅,还要弹出自己的对话框来结束。并且发送报告,去掉了系统默认的发送报告的对话框。

所以一拍脑袋,想让自己的程序崩溃的体面一点。

自己想了大概的思路,觉得可以用一个进程来监控目标程序。的确也可以拿到了目标程序崩溃的信息,知道它什么时候崩溃的,也可以做额外的操作,但是这样是没办法把默认的发送错误的对话框去掉的。

然后又有人说是不是采用了类似钩子的方法把这个东西在哪里勾掉了。

最后网上查了一番,发现SetUnhandledExceptionFilter这个函数解决了一切。

总结了下搜到的资料,这个函数的返回值有三种情况:

EXCEPTION_EXECUTE_HANDLER equ 1 表示我已经处理了异常,可以优雅地结束了  
EXCEPTION_CONTINUE_SEARCH equ 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序显示一个错误框,并结束  
EXCEPTION_CONTINUE_EXECUTION equ -1 表示错误已经被修复,请从异常发生处继续执行

具体使用方法如下:

#include   <windows.h>   
    
  long   __stdcall   callback(_EXCEPTION_POINTERS*   excp)   
  {   
  MessageBox(0,"Error","error",MB_OK);   
  printf("Error   address   %x/n",excp->ExceptionRecord->ExceptionAddress);   
  printf("CPU   register:/n");   
  printf("eax   %x   ebx   %x   ecx   %x   edx   %x/n",excp->ContextRecord->Eax,   
  excp->ContextRecord->Ebx,excp->ContextRecord->Ecx,   
  excp->ContextRecord->Edx);   
  return   EXCEPTION_EXECUTE_HANDLER;   
  }
    
  int   main(int   argc,char*   argv[])   
  {   
  SetUnhandledExceptionFilter(callback);   
  _asm   int   3   //只是为了让程序崩溃
  return   0;   
  }

vs 调试dump

貌似只有vs 05以上的版本,能调试dump文件。

1. dump文件和pdb文件的匹配问题

>> 发布二进制文件时生成的pdb文件一定要保留,只有当发布的二进制文件和pdb文件是同时生成的才好正确调试。

2. dump文件和pdb文件放在哪里的问题

>> 如果dump文件和pdb文件放在同一个目录,则可直接运行调试;当然也可以不是同一个目录,那么在启动dmp文件后,需要设置一下vs的符号文件路径:Tools->Options->Debugging->Symbols. 如果需要调试windows自带的一些dll或者exe,则可以在这里添加windows的pdb文件服务器:http://msdl.microsoft.com/download/symbols

3. 二进制文件放在哪里的问题

>> 现场恢复需要二进制文件,但不必所有的二进制文件都需要,所以即使你的机器和用户的机器操作系统不一样也没关系;出问题的如果是你发布的二进制文件,则只需要你发布的二进制文件就可以了。vs在加载二进制的文件失败的时候会打印出其详细路径,但这是用户机器上的路径,没有必要一定要跟这个路径一样,把你发布的二进制文件放到dump文件目录就可以了。

4. 显示不了源代码的问题

>> 首先需要设置源代码目录,右键solution:Properties->Common Properties->Debug Source Files,里边加入你的本地源代码目录就是了;但是如果代码已经改过了,恢复不到当时的状态,vs显示不了源码怎么办?只要设置:Tools->Options->Debugging->General->Require source files to exactly match the original version 这个复选框钩掉就可以了

Minidump方式保留程序崩溃现场

在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。因为release版本来就少了很多调试信息,更何况一般都是发布出去由用户使用,crash的现场很难保留和重现。目前有一些方法可以解决:崩溃地址 + MAP文件;MAP文件;SetUnhandledExceptionFilter + Minidump。本文重点解决Minidump方式。

一、Minidump文件生成

1、Minidump概念

minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在系统属性 -> 高级 -> 启动和故障恢复 -> 设置 -> 写入调试信息中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。

我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性,dump文件是压缩过的。

2、生成minidump文件

通过drwtsn32、NTSD、CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD、CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD、CDB等调试工具。根据MiniDumpWriteDump接口,完全可以程序自动生成Dump文件。

3、  自动生成Minidump文件

当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。MSDN中描述为:

Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.

因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。

生成dump文件类(minidump.h)#pragma once

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

<em id="__mceDel"

   

  

#include <windows.h> 

  

#include <imagehlp.h> 

  

#include <stdlib.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: <br>    { 

         if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)  

             if(!IsDataSectionNeeded(pInput->Module.FullPath))  

                pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);   <br>    

    }<br>    break;

    case IncludeModuleCallback: 

    case IncludeThreadCallback: 

    case ThreadCallback: 

    case ThreadExCallback: 

       return TRUE; 

  

    default:<br>      break

  

    

    return FALSE; 

  

//创建Dump文件 

  

inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName) 

    HANDLE hFile = CreateFile(strFileName, 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)0x0000ffff; 

  

       MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci); 

  

       CloseHandle(hFile);  

    

  

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) 

    return NULL; 

  

BOOL PreventSetUnhandledExceptionFilter() 

    HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); 

  

    if (hKernel32 ==   NULL) 

       return FALSE; 

  

    void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); 

  

    if(pOrgEntry == NULL) 

       return FALSE; 

    unsigned char newJump[ 100 ]; 

  

    DWORD dwOrgEntryAddr = (DWORD) pOrgEntry; 

  

    dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far 

 

    void *pNewFunc = &MyDummySetUnhandledExceptionFilter; 

  

    DWORD dwNewEntryAddr = (DWORD) pNewFunc; 

    DWORD dwRelativeAddr = dwNewEntryAddr -  dwOrgEntryAddr; 

    newJump[ 0 ] = 0xE9;  // JMP absolute 

    memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc)); 

    SIZE_T bytesWritten; 

    BOOL bRet = WriteProcessMemory(GetCurrentProcess(),    pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten); 

    return bRet; 

  

LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException) 

{

    TCHAR szMbsFile[MAX_PATH] = { 0 }; 

    ::GetModuleFileName(NULL, szMbsFile, MAX_PATH); 

    TCHAR* pFind = _tcsrchr(szMbsFile, '\\'); 

 

    if(pFind) 

    

       *(pFind+1) = 0; 

  

       _tcscat(szMbsFile, _T("CreateMiniDump.dmp")); 

  

       CreateMiniDump(pException,szMbsFile); 

  

    

  

    // TODO: MiniDumpWriteDump 

    FatalAppExit(-1,  _T("Fatal Error")); 

    return EXCEPTION_CONTINUE_SEARCH; 

  

//运行异常处理 

  

void RunCrashHandler() 

    SetUnhandledExceptionFilter(UnhandledExceptionFilterEx); 

    PreventSetUnhandledExceptionFilter(); 

</em>

  

//测试实现文件

// 一个有函数调用的类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

class CrashTest

{

public:

    void Test()

    {

       Crash();

    }

private:

    void Crash()

    {

         strcpy(NULL,"adfadfg");

    }

};

int _tmain(int argc, _TCHAR* argv[])

{

    //设置异常处理函数

    RunCrashHandler();

    CrashTest test;

    test.Test();

    getchar();

    return 0;

}

  

注意事项

1、需要配置debug选项,在C/C++选项à常规à调试信息格式(设置为程序数据库(/Zi));在连接器选项—>调试à生成调试信息(设置为是);C/C++选项à优化à禁用。(参见下图)

2、  可执行文件(exe)必须找到dbghelp.dll,才能生成Dump文件。这个DLL可以从调试工具包中找到。

3、*.exe、*.pdb、*.dump、dbghelp.dll 这四个文件需要放在同一目录下才好调试,双击dump文件时,就可以自动关联到出错代码位置。

4、为了获取更多更深入的调试信息,需要把程序优化开关设置成禁用。

5、 当异常代码定位成功以后,如果无法阻止异常的产生,可以用 __try 结构包装异常代码,__try 和 try 不同,前者可以捕获非法指针产生的异常。

__try {

// 会异常的函数

}

__except( EXCEPTION_EXECUTE_HANDLER ){

// 异常处理

}

二、调试Minidump文件

  1. 双击minidump文件(*.dmp)。默认会启动vs2008。
  2. 菜单Tools/Options, Debugging/Symbols,增加PDB文件路径。注:如果minidump文件与pdb文件在同一目录,就不用设置这个了。
  3. 若调试的程序需要微软基础库的PDB信息,可以增加一个路径为:
  4. http://msdl.microsoft.com/download/symbols
  5. 在界面下方Cache Symbol From symbol…选择本地存储这些Symbols的路径。 注:如果本地已存储过微软基础库的pdb,就直接按照此步操作设置本地路径,不必执行上一步操作了。
  6. 设置代码路径:

设置代码路径:

刚打开的dmp工程,进入解决方案的属性。在这里输入源程序的代码路径。注:一定是sln所在的路径,而不是vcproj的路径!

按F5,debug吧。

demo代码下载:http://download.csdn.net/detail/byxdaz/7349325

调试方法不用上述那么麻烦,直接在Debug目录下 或者 Release目录下 exe + pdb + dmp 在同一目录,然后双击dmp文件VC2010就可以打开,然后点击右上角的调试按钮就可以直接定位到崩溃的代码了;

参考这里: http://blog.csdn.net/starlee/article/details/6630816

别人机器上的dump调试:

http://blog.csdn.net/xhk456/article/details/7523150

这段时间突然发现,要一下做一个金刚不坏之身的程序是不太可能滴,至于对我来说吧。
这个程序也要经过千锤百炼才能够练就一个强大的自信心。

我现在做系统就不考虑一下把程序做的足够强壮了,因为我也做不到,现在做系统时,总考虑的一个问题:

当系统异常的时候怎么去处理?

我不怕系统程序出现异常,甚至直接Over,只要能在异常时处理异常后继续运作,在崩溃重启后能够继续把没

干的活给干了,那么这个在我能够承受的范围内,也在大多数客户的承受范围内,因为这样就是我们所说的将

损失减小到最低,其实是不是最低只有自己能够知道。

当然了,我更希望能够做出一个健壮无比的牛逼程序,所以我想知道程序是在什么情况下崩溃的,可是有些问题

你懂的,老在客户机器上或者生产环境下出现,却在自己的机器上和测试环境就他妈的不出现,遇见这种情况我是

跳楼或者杀人的心情都有了,偶尔我也犯过情绪,想提出辞职申请,换个行业去,告别这苦逼的程序员生涯,

可总不知道是什么力量支持着我,让我坚强依旧滴做着程序员,过着狗日的日子。

后来,不经意间,一位同事给我说了一个种在系统中异常或者崩溃的时候,来生成dump文件,然后用调试器来调试。

这样就可以在生产环境中的dmp文件,拷贝到自己的开发机器上,调试就可以找到错误的位置,配合程序调试符号pdb文件,

直接可以定位到源代码中位置,真是太他妈的神奇了,虽然Release版本下的很多变量的值是不对滴,但并不影响我这个

这么有执着心的coder来找bug。

同事给了我他写的示例,往空指针拷贝数据,在非调试下运行后,果然的崩了,果断滴生成了一个扩展名为dmp的文件,

然后他用vs2010打开那个dmp文件,vs2010很果断滴定位到了那个往空指针拷贝数据那里。

看他那娴熟的操作,顿时感觉到了他的强大和微软的牛逼。

后来我就学他,在程序中加入程序异常时产生dump文件的功能,待系统发布后,在一次不经意间一个程序挂掉了。

在客户的谩骂中,我面带笑容说:这个问题很好解决。我满怀信心滴从服务器上拷贝了程序崩溃产生dump文件,

然后学着那个同事用vs2010打开,我了个去,咋没有定位到源代码中内,只定位到了可执行文件的一个地址,这让哥

情何以堪呐!

还好,我对pdb了解还比较熟悉,想来应该是符号文件的问题,于是就开始摸索的,不经意见的在

堆栈处右击了下,发现菜单里竟然有“加载符号”,而且还有“符号路径”,我想这大概就是让我来选择

对应的pdb文件吧,顿时感觉曙光就在前面。

点击了“符号路径”后如下图:

才发现了,它并不是来选择符号文件,而是选择对应的可执行程序的路径,选择了后果断滴定位到了源代码的位置,

才发现一个很简单很美丽的bug,修改后,在测试后重现发布,系统的健壮性又提高了一个台阶。

回头想了想,我同事给我演示的时候,他程序运行的目录和就是他直接用vs2010生成的目录,所以此种情况下

用vs2010打开dmp文件即可定位到源代码文件。而发布后的程序,一般情况下你根本不知道别人放在什么地方去执行的,

因此调试时还并必须选相同版本的可执行文件,然后pdb文件才会好好工作,要不没可执行文件,咋个调试嘛。

哎,这同事,居然还留了一手,坑爹啊。

不过还是要感谢他滴,我又掌握了一些东西,又增强了我这个苦逼程序员写好程序的信心。

在写这个之前看了相关文章,感觉比较好的推荐一哈:

http://www.cppblog.com/woaidongmao/archive/2011/05/10/146086.html

到这里,你就可以在你的工程中通过代码的方式添加,在程序崩溃的时候回创建dump文件了;

.dump

.dump 命令创建一个用户模式或内核模式崩溃转储文件。分析工具:https://msdn.microsoft.com/en-us/library/windows/desktop/ee416349(v=vs.85).aspx#writing_a_minidump

程序崩溃(crash)的时候, 为了以后能够调试分析问题, 可以使用WinDBG要把当时程序内存空间数据都保存下来,生成的文件称为dump 文件。 步骤:

1) 打开WinDBG并将之Attach 到crash的程序进程

2) 输入产生dump 文件的命令

直接用.dump -?可以看到它的简单说明:

[cpp] view plaincopy

  1. 0:000> .dump -?
  2. Usage: .dump [options] filename
  3. Options are:
  4. /a - Create dumps for all processes (requires -u)
  5. /b[a] - Package dump in a CAB and delete dump
  6. /c <comment> - Add a comment (not supported in all formats)
  7. /j <addr> - Provide a JIT_DEBUG_INFO address
  8. /f - Create a legacy style full dump
  9. /m[acdfFhiprRtuw] - Create a minidump (default)
  10. /o - Overwrite any existing file
  11. /u - Append unique identifier to dump name

/o :覆盖具有相同名字的dump文件。如果没有使用该选项又存在一个相同名字的文件,则dump文件不会被写入:比如我的C盘原有一个myapp.dmp文件:

[cpp] view plaincopy

  1. 0:000> .dump c:/myapp.dmp
  2. Unable to create file 'c:/myapp.dmp' - Win32 error 0n80
  3. "文件存在。"
  4. 0:000> .dump /o c:/myapp.dmp
  5. Creating c:/myapp.dmp - mini user dump
  6. Dump successfully written

/f (用户模式:) 创建一个完整用户模式dump,这里要注意不要字面理解,

完整用户模式dump是基本的用户模式dump文件。这种dump文件包含进程的完整内存空间、程序本身的可执行映像、句柄表和其他对调试器有用的信息

注意 和名字无关,最大的"minidump"文件实际上可以提供比完整用户模式dump更多的信息。例如,.dump /mf.dump /ma将创建比.dump /f更大更完整的文件。

用户模式下,使用.dump /m[MiniOptions] 是最好的选择。通过这个开关创建的dump文件可以很小也可以很大。通过指定合适的MiniOptions 可以控制究竟需要包含哪些信息。

[cpp] view plaincopy

  1. 0:000> .dump /o/f c:/myapp.dmp
  2. *****************************************************************************
  3. * .dump /ma is the recommend method of creating a complete memory dump      *
  4. * of a user mode process.                                                   *
  5. *****************************************************************************
  6. Creating c:/myapp.dmp - user full dump
  7. Dump successfully written

我们看到了,系统给出了提示:.dump /ma是创建完整dump的推荐方式(用户模式下)

/m[MiniOptions] 创建一个小内存dump(内核模式)或者 minidump (用户模式)。如果没有指定 /f /m ,/m 是默认选项。用户模式下,/m 后面可以跟附加的MiniOptions 用来指定dump文件中包含的数据。如果没有使用MiniOptions ,dump文件包含模块、线程和调用堆栈信息,但是没有其他附加信息

MiniOption 作用
a 创建一个包含所有附加选项的minidump。/ma选项相当于/mfFhut —它会在minidump中添加完整的内存数据、句柄数据、已卸载模块信息、基本内存信息和线程时间信息。
f 在minidump中包含完整内存数据。目标程序拥有的所有 可访问的已交付的页面(committed pages)都会包含进去。
F 在minidump中添加所有基本内存信息。这会将一个流加入到包含完整基本内存信息的minidump中,而不单是可使用的内存。这样可以使得调试器能够重建minidump生成时进程的完整虚拟内存布局。
h 在minidump中包含和目标进程相关的句柄信息。
u 在minidump中包含已卸载模块信息。仅在Windows Server 2003和之后版本的Windows中可用。
t 在minidump中包含附加的线程信息。包括可以在调试minidump时使用!runaway扩展命令或.ttime (Display Thread Times)命令进行显示的线程时间。
i 在minidump中包含次级内存(secondary memory)。次级内存是由堆栈中的指针或备份存储(backing store)中引用到的任何内存,加上该地址周围的一小段区域。
p 在minidump中包含进程环境块(PEB)和线程环境块(TEB)。这在想访问程序的进程和线程相关的Windows系统信息时很有用。
w 将所有已交付的可读写的私有页面包含进minidump。
d 在minidump中包含可执行映像中所有可读写的数据段。
c 加入映像中的代码段。
r 从minidump中去掉对重建调用堆栈无用的堆栈和存储内存部分。局部变量和其他数据类型值也被删除。这个选项不会使得minidump变小(因为这些内存节仅仅是变成0),但是当想保护其他程序中的机密信息时有用。
R 在minidump中去掉完整的模块路径。仅包含模块名。如果想保护用户的目录结构时该选项有用。

选项(1): /m

命令行示例:.dump /m C:/dumps/myapp.dmp

注解: 缺省选项,生成标准的minidump, 转储文件通常较小,便于在网络上通过邮件或其他方式传输。 这种文件的信息量较少,只包含系统信息、加载的模块(DLL)信息、 进程信息和线程信息。

选项(2): /ma

命令行示例:.dump /ma C:/dumps/myapp.dmp

注解: 带有尽量多选项的minidump(包括完整的内存内容、句柄、未加载的模块,等等),文件很大,但如果条件允许(本机调试,局域网环境), 推荐使用这中dump。

选项(3):/mFhutwd

命令行示例:.dump /mFhutwd C:/dumps/myapp.dmp

注解:带有数据段、非共享的读/写内存页和其他有用的信息的minidump。包含了通过minidump能够得到的最多的信息。是一种折中方案。

Fhutwd按字母对应上面的MiniOptions表示

//-xp自动生成dump-----------------------------------------------------------------------------------------------------------------------------------------------------------------

那怎么自动生成dump文件呢,比如对方的电脑没有windbg,这里用到一个window XP系统自带工具,Dr.Watson

运行方式很简单:

直接run-输入drwtsn32 -i就可以了,会提示这样的:

这个命令真难记,实话,记华生医生吧,福尔摩斯中的

如果有程序崩溃,会自动生成dump,这时再输入drwtsn32就会运行这个程序:

找到对应路径的DMP文件就行了,一般放在如下路径:
C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson

//-win7自动生成dump-----------------------------------------------------------------------------------------------------------------------------------------------------------------

win7下需打开regedit--> 找到:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting]

在它下面加一项LocalDumps,并做如下项配置:

Value 描述 Type 默认值
DumpFolder 文件保存路径 REG_EXPAND_SZ %LOCALAPPDATA%CrashDumps
DumpCount dump文件的最大数目 REG_DWORD 10
DumpType 指定生成的dump类型:
0:Custom dump
1:Mini dump
2:Full dump
REG_DWORD 1
CustomDumpFlags 仅在DumpType为0时使用
为MINIDUMP_TYPE的组合
REG_DWORD
MiniDumpWithDataSegs|
MiniDumpWithUnloadedModules|
MiniDumpWithProcessThreadData

可以写成.bat:

[cpp] view plaincopy

  1. @echo off
  2. echo 设置Dump...
  3. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps"
  4. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d "C:\MyDump" /f
  5. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f
  6. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f
  7. echo Dump已经设置
  8. pause
  9. @echo on

[cpp] view plaincopy

  1. @echo off
  2. echo 正在取消设置Dump...
  3. reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /f
  4. echo Dump已经取消设置
  5. pause
  6. @echo on

LocalDumps是全局的,如果想针对指定进程单独设置,如test1.exe,则在/LocalDumps下新建子项test1.exe,同时在test1目录下复制上表的选项,这样,系统就会先读全局设置,再读子项test1.exe的设置

在Windows 7上可以由多个方法产生dump文件:

转一篇文章:

Windows调试 - 如何使用dump文件

如何使用dump文件

我最近在开发一个windows下的程序(win7/win8),有一些case下会crash,如果在自己开发机器上调试比较简单:运行程序,然后vs attach到进程上即可,但是在每台QA的机器上安装vs时不现实的,因此我们要用到dump文件。

微软网站有一篇文章讲述如何创建dump文件:

http://support.microsoft.com/kb/931673

第一种: 通过任务管理器:这种适用在程序挂了(crash)的时候进程还未退出,比如我运行程序,出现了下面的错:

此时打开任务管理器,右击相应进程,点击"Create Dump File“:

一会创建完成:

然后把这个DMP文件拷到开发机器上,用VS打开: 会出现下面的界面,要想知道发生错误时候的调用栈,需要设置symbol的路径,点击”Set Symbol Paths“:

注意这个pdb要对应于crash的exe,否则调用栈没法显示:

设置完成后,点击”Debug with Native Only“ 你就可以看到调用栈了。

第二种: 改注册表

如果程序crash的时候没有框蹦出来,可以通过改注册表的设置让操作系统在程序crash的时候自动生成dump,并放到特定的目录下

[plain] view plaincopy

  1. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps
  2. Value Name = DumpType
  3. Data type: REG_DWORD
  4. Value Data = 1

其中Value Data=1代表的含义是:

[plain] view plaincopy

  1. 0 = Create a custom dump
  2. 1 = Mini dump
  3. 2 = Full dump

设置完成后,crash发生时,操作系统生成dump,路径在%LOCALAPPDATA%\CrashDumps下,详细可以参考:

http://msdn.microsoft.com/en-us/library/bb787181%28v=VS.85%29.aspx

(完)

最简单的方法,应用dump文件,就是修改注册表,这样每一个程序就自动回创建dump文件;

下面给出修改注册表的reg文件:

注意修改cdb.exe路径,和自己计算机上的一致;

将下面的内容保存到txt文本中,然后修修改txt为reg,然后保存,双击reg文件,导入到注册表就可以了;

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
"Auto"="1"
"Debugger"="\"D:\\Program Files\\Debugging Tools for Windows (x86)\\cdb.exe\" -p %ld -e %ld -c \".dump /ma /u C:\\crash.dmp;q\""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]
"DbgJITDebugLaunchSetting"=dword:00000002
"DbgManagedDebugger"="\"D:\\Program Files\\Debugging Tools for Windows (x86)\\cdb.exe\" -p %ld -e %ld -c \".dump /ma /u C:\\crash.dmp;q\""

[转]window下使用SetUnhandledExceptionFilter捕获让程序的崩溃相关推荐

  1. linux系统读取excel文件是否存在,小弟我用poi读excel,在window下没有有关问题,但把程序放到linux上时,读取客户端的excel文件报错,不...

    我用poi读excel,在window下没有问题,但把程序放到linux上时,读取客户端的excel文件报错,不知道如何解决 我用poi读excel,在window下没有问题,但把程序放到linux上 ...

  2. window下使用nw.js开发桌面应用程序环境的搭建

    安装node window下去node官网下载长期支持版本或者最新稳定版都可以. 按装nw用来管理和按装nw.js npm install -g nrm # 用来设置npm镜像地址 npm insta ...

  3. 一个window下的简单的全局快捷键向指定的进程发送的c代码与exe程序下载(二)

    c代码:一个window下的简单的全局快捷键向指定的进程发送的c代码与exe程序下载 -----------------这是文件 hotkey.zip base64后的字符,复制代码时不要复制我(共2 ...

  4. [Kafka错误]-----kafka在window下出现另一个程序正在使用此文件,进程无法访问的错误

    目录 前言------对于只想解决这个问题的程序猿们,可以直接跳到"解决" 1.背景 2.问题 3.原因 4.解决(尾部有提供编译好的kafka包下载链接) 4.1kafka补丁版 ...

  5. 返回键捕获 应用程序退出的两种方式(转)

    作为应用程序一个较好的用户体验应该是:在退出应用程序前询问用户是否真正退出?目前普遍做法是,一在退出前询问是否真正退出,二是连续按两下退出. 返回键捕获 应用程序退出的两种方式 实现上述两种应用退出方 ...

  6. window下安装Memcache

    说来惭愧,从事PHP已经1年多了,但是很多PHP相关的知识都不知道. 前一阵子看到网上流传了很久的面试题,才了解到原来还有memcache这么个东西-_-. memcache 具体是什么Google一 ...

  7. linux 查询注册服务,window下注册服务的命令小结

    1. 描述:     SC 是用于与服务控制管理器通信的命令行程序 . 用法: sc [command] [service name] ... 选项 的格式为 可以键入 "sc [comma ...

  8. Window下UDP(socket)接和收数据案例

     配置QT的环境变量,这台电脑à属性à高级系统设置à高级à环境变量à系统变量àpathàC:\Qt\Qt5.3.0\5.3\mingw482_32\bin;C:\Qt\Qt5.3.0\Tools\ ...

  9. window 下内存泄漏检测

    在window 下开发进行内存泄漏的检测相对比较容易. 这里只是简单的记录一些东西,没有具体的谈论实现. window 下面内存检测主要可以考虑从两个方面入手,这两个方面并不是一个if else 分支 ...

最新文章

  1. 高级bash脚本编程(1)
  2. winform中捕获程序未处理的所有异常
  3. 初学__Python——Python数据类型之文件
  4. JavaSE、JavaEE与Spring的概念和异同点剖析
  5. 关于LBS坐标系与精度的问题
  6. linux sudo永久免密码,linux 免密码 使用sudo 直接使用root权限执行命令
  7. td 超出宽度隐藏_table中td文字超出长度用省略号隐藏超出内容,鼠标点击内容全部显示...
  8. Linux系统LVM增加新硬盘实现根文件系统扩容
  9. 清华女生破解北斗?中国最年轻女博导揭秘背后实情
  10. 论.NET反射、委托与模式关系 zt- -
  11. 半导体芯片产业链公司大全
  12. linux下安装rabbitMQ和springboot+rabbitMQ使用案例
  13. 人名和成绩一起排序_Excel怎么按姓名笔画和拼音排序,后面的数字跟着一起变动...
  14. PPT背景色问题:白色变绿色?
  15. mendeley引用参考文献不显示_手把手教你一步搞定引用参考文献,超级强大且使用的文献管理器...
  16. 快慢指针 ——链表 | Leetcode 练习
  17. python爬取淘宝商品做数据挖掘
  18. 使整个网站变黑白(灰色)的特效代码
  19. blood pressure android app,Blood Pressure Monitor via Bluetooth/Internet in Android
  20. make,makefile和脚本之间什么关系?makefile是一种脚本吗?【转】

热门文章

  1. android系统级别推送,安卓10.0即将推送,等着升级系统吧,望周知!
  2. java smtp pop3_JavaMail(二):smtp,pop3命令
  3. HTML中input的用法
  4. Graphics2D 图片上添加图片或绘制二维码
  5. TensorFlow Adding visible gpu devices: 0 加载GPU速度慢
  6. python人像精细分割_python 人像分割问题 foreground
  7. luogu 1181
  8. 一种嵌入式设备串口加密协议
  9. 只知道HDFS和GFS?你其实并不懂分布式文件系统
  10. 访问页面URL的常用方法