编写的windows程序,崩溃时产生crash dump文件的办法

一、引言

dump文件是C++程序发生异常时,保存当时程序运行状态的文件,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件便成了我们查找错误的最后一根救命的稻草。windows程序产生dump文件和linux程序产生dump文件的方式不一样,linux默认是不让产生core dump文件,只要在用户自己的~/.bash_profile文件中增加

ulimit -S -c unlimited > /dev/null 2>&1

这样程序崩溃就可以产生可调试的core dump文件了。但是windows环境就得写代码才能实现了。

二、原理

windows程序当遇到异常,没有try-catch或者try-catch也无法捕获到的异常时,程序就会自动退出,如果这时候没有dump文件的话,我们是没有得到任何程序退出的信息。在windows程序异常退出之前,会预先调用一个在程序中注册的异常处理回调函数(默认是没有设置),只要我们在这个回调函数中调用MiniDumpWriteDump函数就可以产生我们想要的dump文件。

三、实现

1.调用SetUnhandledExceptionFilter注册一个自定义的异常处理回调函数

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

异常处理回调函数的原型

LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);

2.CreateFile创建dump文件,调用MiniDumpWriteDump函数往dump文件写异常信息

[cpp] view plain copy
 print?
  1. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
  2. {  
  3.     HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
  4.         FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  5.   
  6.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
  7.     {  
  8.         MINIDUMP_EXCEPTION_INFORMATION mdei;  
  9.         mdei.ThreadId           = GetCurrentThreadId();  
  10.         mdei.ExceptionPointers  = pep;  
  11.         mdei.ClientPointers     = NULL;  
  12.   
  13.         MINIDUMP_CALLBACK_INFORMATION mci;  
  14.         mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
  15.         mci.CallbackParam       = 0;  
  16.   
  17.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
  18.   
  19.         CloseHandle(hFile);  
  20.     }  
  21. }  

CreateMiniDump函数是在异常处理回调函数MyUnhandledExceptionFilter中调用的

[cpp] view plain copy
 print?
  1. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
  2. {  
  3.     CreateMiniDump(pExceptionInfo, "core.dmp");  
  4.   
  5.     return EXCEPTION_EXECUTE_HANDLER;  
  6. }  

3.将SetUnhandledExceptionFilter失效

vs2005中,编译的过程中,编译器会自动给你的程序加上一句SetUnhandledExceptionFilter(NULL),这就会导致你之前自定义的

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

无效,就有可能不会产生dump文件,因此我们必须在自定义的SetUnhandledExceptionFilter之后,让之后调用的SetUnhandledExceptionFilter无效。增加以下代码:

[cpp] view plain copy
 print?
  1. // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效  
  2. void DisableSetUnhandledExceptionFilter()  
  3. {  
  4.     void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),  
  5.         "SetUnhandledExceptionFilter");  
  6.   
  7.     if (addr)  
  8.     {  
  9.         unsigned char code[16];  
  10.         int size = 0;  
  11.   
  12.         code[size++] = 0x33;  
  13.         code[size++] = 0xC0;  
  14.         code[size++] = 0xC2;  
  15.         code[size++] = 0x04;  
  16.         code[size++] = 0x00;  
  17.   
  18.         DWORD dwOldFlag, dwTempFlag;  
  19.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);  
  20.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);  
  21.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);  
  22.     }  
  23. }  

最终代码整理:

//minidump.h

[cpp] view plain copy
 print?
  1. #pragma once  
  2. #include <windows.h>  
  3. #include <DbgHelp.h>  
  4. #include <stdlib.h>  
  5. #pragma comment(lib, "dbghelp.lib")  
  6.   
  7. #ifndef _M_IX86  
  8. #error "The following code only works for x86!"  
  9. #endif  
  10.   
  11. inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)  
  12. {  
  13.     if(pModuleName == 0)  
  14.     {  
  15.         return FALSE;  
  16.     }  
  17.   
  18.     WCHAR szFileName[_MAX_FNAME] = L"";  
  19.     _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);  
  20.   
  21.     if(wcsicmp(szFileName, L"ntdll") == 0)  
  22.         return TRUE;  
  23.   
  24.     return FALSE;  
  25. }  
  26.   
  27. inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,  
  28.                                       const PMINIDUMP_CALLBACK_INPUT   pInput,  
  29.                                       PMINIDUMP_CALLBACK_OUTPUT        pOutput)  
  30. {  
  31.     if(pInput == 0 || pOutput == 0)  
  32.         return FALSE;  
  33.   
  34.     switch(pInput->CallbackType)  
  35.     {  
  36.     case ModuleCallback:  
  37.         if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)  
  38.             if(!IsDataSectionNeeded(pInput->Module.FullPath))  
  39.                 pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);  
  40.     case IncludeModuleCallback:  
  41.     case IncludeThreadCallback:  
  42.     case ThreadCallback:  
  43.     case ThreadExCallback:  
  44.         return TRUE;  
  45.     default:;  
  46.     }  
  47.   
  48.     return FALSE;  
  49. }  
  50.   
  51. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
  52. {  
  53.     HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
  54.         FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  55.   
  56.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
  57.     {  
  58.         MINIDUMP_EXCEPTION_INFORMATION mdei;  
  59.         mdei.ThreadId           = GetCurrentThreadId();  
  60.         mdei.ExceptionPointers  = pep;  
  61.         mdei.ClientPointers     = NULL;  
  62.   
  63.         MINIDUMP_CALLBACK_INFORMATION mci;  
  64.         mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
  65.         mci.CallbackParam       = 0;  
  66.   
  67.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
  68.   
  69.         CloseHandle(hFile);  
  70.     }  
  71. }  
  72.   
  73. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
  74. {  
  75.     CreateMiniDump(pExceptionInfo, "core.dmp");  
  76.   
  77.     return EXCEPTION_EXECUTE_HANDLER;  
  78. }  
  79.   
  80. // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效  
  81. void DisableSetUnhandledExceptionFilter()  
  82. {  
  83.     void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),  
  84.         "SetUnhandledExceptionFilter");  
  85.   
  86.     if (addr)  
  87.     {  
  88.         unsigned char code[16];  
  89.         int size = 0;  
  90.   
  91.         code[size++] = 0x33;  
  92.         code[size++] = 0xC0;  
  93.         code[size++] = 0xC2;  
  94.         code[size++] = 0x04;  
  95.         code[size++] = 0x00;  
  96.   
  97.         DWORD dwOldFlag, dwTempFlag;  
  98.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);  
  99.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);  
  100.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);  
  101.     }  
  102. }  
  103.   
  104. void InitMinDump()  
  105. {  
  106.     //注册异常处理函数  
  107.     SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);  
  108.   
  109.     //使SetUnhandledExceptionFilter  
  110.     DisableSetUnhandledExceptionFilter();  
  111. }  

4.测试代码

//test.cpp

[cpp] view plain copy
 print?
  1. #include <iostream>  
  2. #include "minidump.h"  
  3. void test()  
  4. {  
  5.     std::string s = "abcd";  
  6.   
  7.     try{  
  8.         s[100] = 'b';  
  9.     }  
  10.     catch(std::exception& e)  
  11.     {  
  12.         std::cout << "with exception:[" << e.what() << "]" << std::endl;  
  13.     }  
  14.     catch(...)  
  15.     {  
  16.         std::cout << "with unknown exception" << std::endl;  
  17.     }  
  18. }  
  19.   
  20. void main()  
  21. {  
  22.     InitMinDump();  
  23.   
  24.     test();  
  25.   
  26.     system("pause");  
  27. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458715.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx+PHP实时生成不同尺寸图片

原来图片服务器采用Windows .net架构&#xff0c;鉴于需求需要生成各种尺寸图片。流程说明:用户从Nginx请求对应的图片,判断是否存在_200x300的对应参数&#xff0c;如果没有就直接请求到对应目录的原图&#xff0c;否则继续判断是否在本地已经生成了对应的缓存图片&#xff0c…

JavaScript设计模式 Item 2 -- 接口的实现

1、接口概述 1。什么是接口&#xff1f; 接口是提供了一种用以说明一个对象应该具有哪些方法的手段。尽管它可以表明这些方法的语义&#xff0c;但它并不规定这些方法应该如何实现。 2. 接口之利 促进代码的重用。 接口可以告诉程序员一个类实现了哪些方法&#xff0c;从而帮助…

Spring Boot 乐观锁加锁失败 - 集成AOP

Spring Boot with AOP 手头上的项目使用了Spring Boot&#xff0c; 在高并发的情况下&#xff0c;经常出现乐观锁加锁失败的情况&#xff08;OptimisticLockingFailureException&#xff0c;同一时间有多个线程在更新同一条数据&#xff09;。为了减少直接向服务使用者直接返回…

掌握VS2010调试 -- 入门指南

1 导言 在软件开发周期中&#xff0c;测试和修正缺陷&#xff08;defect&#xff0c;defect与bug的区别&#xff1a;Bug是缺陷的一种表现形式&#xff0c;而一个缺陷是可以引起多种Bug的&#xff09;的时间远多于写代码的时间。通常&#xff0c;debug是指发现缺陷并改正的过程。…

151031

create or replace procedure pr_test1 is v_case number(3): 100; beginif 2>1 thendbms_output.put_line(成立);elsif 4>3 thenif 7>6 thendbms_output.put_line(不成立);end if; elsif 6>5 thendbms_output.put_line(也行);elsedbms_output.put_line(也不成立);…

postgresql9.5 run 文件linux安装后配置成开机服务

网上出现的比较多安装方法要么是源码安装&#xff0c;要么是yum安装&#xff0c;我发觉都要配置很多属性&#xff0c;比较麻烦&#xff0c;所以现在我在centos7长用 run文件来安装 http://get.enterprisedb.com/postgresql/postgresql-9.5.1-1-linux-x64.run 这里的安装shell整…

Windows API GetProcAddress 及demo code

GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。 函数原型&#xff1a; FARPROC GetProcAddress( HMODULE hModule, // DLL模块句柄 LPCSTR lpProcName// 函数名 ); 参数&#xff1a; hModule [in] 包含此函数的DLL模块的句柄。LoadLibrary、AfxLoadLibrary …

【操作系统】进程管理

进程管理 进程的基本概念 程序的顺序执行及其特征 程序的顺序执行:仅当前一操作(程序段)执行完后&#xff0c;才能执行后续操作。 程序顺序执行时的特征&#xff1a;顺序性&#xff0c;封闭性&#xff0c;可再见性。 前趋图 前趋图(Precedence Graph)是一个有向无循环图&#…

va_list va_start va_end的使用

<pre name"code" class"cpp" style"color: rgb(51, 51, 51); white-space: pre-wrap; word-wrap: break-word;"><strong>一、 从printf()开始</strong> 从大家都很熟悉的格式化字符串函数开始介绍可变参数函数。 原型&#xf…

Linux学习之CentOS(三)----将Cent0S 7的网卡名称eno16777736改为eth0

【正文】 Linux系统版本&#xff1a;CentOS_7&#xff08;64位&#xff09; 一、前言&#xff1a; 今天又从Centos 6.5装回了Centos 7&#xff0c;毕竟还是要顺应潮流嘛。安装完成之后&#xff0c;发现发现CentOS 7默认的网卡名称是eno16777736&#xff0c;如图所示&#xff1a…

本地音频播放,使用AVFoundation.framework中的AVAudioPlayer来实现

本地音频播放,使用AVfoundation.framework中的AVAudioPlayer来实现 /*AVAudioPlayer的使用比较简单: 1、初始化AVAudioPlayer对象&#xff0c;此时通常指定本地文件路径 2、设置播放器属性&#xff0c;例如重复次数、音量大小等 3、调用play方法播放。 */

AngularJS操作DOM——angular.element

addClass()-为每个匹配的元素添加指定的样式类名after()-在匹配元素集合中的每个元素后面插入参数所指定的内容&#xff0c;作为其兄弟节点append()-在每个匹配元素里面的末尾处插入参数内容attr() - 获取匹配的元素集合中的第一个元素的属性的值bind() - 为一个元素绑定一个事…

C++中operator的主要用法

1&#xff0e; operator 用于类型转换函数&#xff1a; 类型转换函数的特征&#xff1a; 1&#xff09; 型转换函数定义在源类中&#xff1b; 2&#xff09; 须由 operator 修饰&#xff0c;函数名称是目标类型名或目标类名&#xff1b; 3&#xff09; 函数没有参数&#x…

声纹识别

一、 声纹识别是一项根据语音波形中反映说话人生理和行为特征的语音参数&#xff0c;自动识别说话人身份的技术。与语音识别不同的是&#xff0c;声纹识别利用的是语音信号中的说话人身份信息&#xff0c;而不考虑语音中的字词意思。由于每个人的生物特征具有与其他人不同的唯一…

Asp.net mvc 实时生成缩率图到硬盘

之前对于缩率图的处理是在图片上传到服务器之后&#xff0c;同步生成两张不同尺寸的缩率供前端调用&#xff0c;刚开始还能满足需求&#xff0c;慢慢的随着前端展示的多样化&#xff0c;缩率图已不能前端展示的需求&#xff0c;所以考虑做一个实时生成图片缩率图服务。 每次调用…

数据库事务的隔离机制

数据库事务(Database Transaction) &#xff0c;是指作为单个逻辑工作单元执行的一系列操作&#xff0c;要么完全地执行&#xff0c;要么完全地不执行。----百度百科就是说你定义一组数据库操作&#xff0c;然后告诉数据库说这些操作要么都成功&#xff0c;要么都不成功。类似于…

如何使用CppUnit进行单元测试

http://www.vckbase.com/document/viewdoc/?id1762 一、前言 测试驱动开发(TDD)是以测试作为开发过程的中心&#xff0c;它坚持&#xff0c;在编写实际代码之前&#xff0c;先写好基于产品代码的测试代码。开发过程的目标就是首先使测试能够通过&#xff0c;然后再优化设计结构…

录制wav格式的音频

项目中有面部认证、声纹认证&#xff0c;服务器端要求上传wav格式的音频&#xff0c;所以写了这样一个小demo。 刚刚开始写博客还不知道怎么上传代码&#xff0c;就复制了&#xff0c;嘻嘻 DotimeManage.h class DotimeManage; protocol DotimeManageDelegate <NSObject&g…

iOS开发网络篇—Reachability检测网络状态

前言&#xff1a;当应用程序需要访问网络的时候&#xff0c;它首先应该检查设备的网络状态&#xff0c;确认设备的网络环境及连接情况&#xff0c;并针对这些情况提醒用户做出相应的处理。最好能监听设备的网络状态的改变&#xff0c;当设备网络状态连接、断开时&#xff0c;程…

网络七层协议 五层模型 TCP连接 HTTP连接 socket套接字

socket&#xff08;套接字&#xff09;是通信的基石&#xff0c;是支持TCP/IP协议的网络通信的基本操作单元&#xff0c;包含进行网络通信必须的五种信息&#xff1a;连接使用的协议&#xff0c;本地主机的IP地址&#xff0c;本地进程的协议端口&#xff0c;远地主机的IP地址&a…