windows下qt程序意外崩溃,生成dump文件的方法

17 篇文章 1 订阅
2 篇文章 0 订阅

程序运行一段时间之后,意外退出,没有提示任何出错信息,这种情况可能是内存泄漏,但是没有提示错误信息,很难定位到具体代码。我们可以生成dump文件,定位出错位置。

在工程中添加代码:

mdump.h

#ifndef MDUMP1_H
#define MDUMP1_H

#include <Windows.h>
#include <DbgHelp.h>

// based on dbghelp.h
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
									CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
									CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
									CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
									);

#define MAX_WARNING_MESSAGE_PATH 1024

class MiniDumper
{
private:
	static LPCWSTR m_szAppName;

	static LPWSTR m_szAppVersion;

	static LPWSTR m_szAppBuildNumber;

	static WCHAR m_szMessageText[MAX_WARNING_MESSAGE_PATH];

	static LPWSTR m_szDumpFilePath;	
	
	static LONG WINAPI TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo );

public:
    MiniDumper( );
	~MiniDumper();
	static void SetVersion(LPCWSTR szVersion);
	static void SetBuildNumber(LPCWSTR szBuildNumber);
	static void SetDumpFilePath(LPCWSTR szFilePath);
	static int SetWarningMessage(LPCWSTR szMessageText)
	{
		if(szMessageText)
		{
			int iLen = wcslen(szMessageText);
			if(iLen < MAX_WARNING_MESSAGE_PATH - MAX_PATH)
			{
				wcscpy(m_szMessageText,szMessageText);
				return 0;
			}			
		}
		return 1;
	}
};


#endif

mdump.cpp

#include <Windows.h>
#include "mdump.h"
#include <QtDebug>

LPCWSTR MiniDumper::m_szAppName;

LPWSTR MiniDumper::m_szAppVersion;

LPWSTR MiniDumper::m_szAppBuildNumber;

WCHAR MiniDumper::m_szMessageText[MAX_WARNING_MESSAGE_PATH];

LPWSTR MiniDumper::m_szDumpFilePath;

#define DEFAULT_ENGLISH_MESSAGE_TEXT L"%s experienced an unknown error and had to exit. \nHowever, some error information has been saved in %s. \nPlease, email this file to <hassan_deldar@yahoo.com> if you would like to help us debug the problem."

#define MAX_DUMP_FILE_NUMBER 9999

 
//static int DUMP_TYPE_MINI = MiniDumpWithUnloadedModules;

//static int DUMP_TYPE_MIDD = MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory;

static int DUMP_TYPE_FULL = MiniDumpNormal | MiniDumpWithFullMemory | MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData;

//static int DUMP_TYPE_FULL = MiniDumpNormal;
//默认值是只有 MiniDumpNormal 文件比较小
//如果把所有的选项都加上, 文件很大, 本机调试也没关系


MiniDumper::MiniDumper()
{
	// if this assert fires then you have two instances of MiniDumper
	// which is not allowed
	Q_ASSERT( m_szAppName==NULL );

    m_szAppName =  wcsdup(L"iLadarDataCollect");
    m_szAppVersion = wcsdup( L"CrashDump");
    m_szAppBuildNumber = wcsdup( L"0000");
	
	wcscpy(m_szMessageText,DEFAULT_ENGLISH_MESSAGE_TEXT);

		
	m_szDumpFilePath = NULL;
	::SetUnhandledExceptionFilter( TopLevelFilter );
}

MiniDumper::~MiniDumper()
{	
}

void MiniDumper::SetVersion(LPCWSTR szVersion)
{
	if(szVersion)
	{
		free(m_szAppVersion);
		m_szAppVersion = wcsdup(szVersion);
	}	
}

void MiniDumper::SetBuildNumber(LPCWSTR szBuildNumber)
{
	if(szBuildNumber)
	{
		free(m_szAppBuildNumber);
		m_szAppBuildNumber = wcsdup(szBuildNumber);
	}
}

void MiniDumper::SetDumpFilePath(LPCWSTR szFilePath)
{
	free(m_szDumpFilePath);
	m_szDumpFilePath = NULL;
	if(szFilePath != NULL)
	{
		m_szDumpFilePath = wcsdup(szFilePath);
	}	
}

LONG MiniDumper::TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo )
{

	LONG retval = EXCEPTION_CONTINUE_SEARCH;
	HWND hParent = NULL;						// find a better value for your app

	// firstly see if dbghelp.dll is around and has the function we need
	// look next to the EXE first, as the one in System32 might be old 
	// (e.g. Windows 2000)
	HMODULE hDll = NULL;
	WCHAR szDbgHelpPath[_MAX_PATH];

	if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
	{
		WCHAR *pSlash = wcsrchr( szDbgHelpPath, L'\\');
		if (pSlash)
		{
			wcscpy( pSlash+1, L"DBGHELP.DLL" );
			hDll = ::LoadLibrary( szDbgHelpPath );
		}
	}

	if (hDll==NULL)
	{
		// load any version we can
		hDll = ::LoadLibrary( L"DBGHELP.DLL");
	}

	LPCWSTR szResult = NULL;

	if (hDll)
	{
		MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
		if (pDump)
		{
			WCHAR szDumpPath[_MAX_PATH];
			WCHAR szDumpRootPath[_MAX_PATH];
			WCHAR szScratch[_MAX_PATH];

			// work out a good place for the dump file
			
            if(m_szDumpFilePath == NULL)
            {
                if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
                {
                    WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
                    if (pSlash)
                    {
                        wcscpy(pSlash + 1, L"");
                        wcscpy(szDumpPath, szDbgHelpPath);
                    }
                }
                else if (!GetTempPath( _MAX_PATH, szDumpPath ))
                    wcscpy( szDumpPath, L"c:\\temp\\" );
            }
            else
            {
                wcscpy( szDumpPath, m_szDumpFilePath );
            }
            wcscpy( szDumpRootPath, szDumpPath);

            //PrintDebug(L"[MiniDumper] Mini Dump file:[%s]",szDumpPath);

			// ask the user if they want to save a dump file
			//if (::MessageBox( NULL, _T("Something bad happened in your program, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
			{
				HANDLE hFile = INVALID_HANDLE_VALUE;
				int i = 1;
				WCHAR szFileNumber[_MAX_PATH];
				while(hFile == INVALID_HANDLE_VALUE)
				{					
					swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d",i);
					wcscpy( szDumpPath, szDumpRootPath);
					wcscat( szDumpPath, m_szAppName );
					wcscat( szDumpPath, L"_" );
					wcscat( szDumpPath, m_szAppVersion);
					wcscat( szDumpPath, L"_" );
					wcscat( szDumpPath, m_szAppBuildNumber);
					wcscat( szDumpPath, szFileNumber);
					wcscat( szDumpPath, L".dmp" );					
                    hFile = CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
											FILE_ATTRIBUTE_NORMAL, NULL );
					i++;
					if(i > MAX_DUMP_FILE_NUMBER)
					{
                        hFile = CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
											FILE_ATTRIBUTE_NORMAL, NULL );
						break;
					}
				}
				// create the file				

				if (hFile!=INVALID_HANDLE_VALUE)
				{
					_MINIDUMP_EXCEPTION_INFORMATION ExInfo;

                    ExInfo.ThreadId = GetCurrentThreadId();
					ExInfo.ExceptionPointers = pExceptionInfo;
					ExInfo.ClientPointers = NULL;

					// write the dump
                    BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)DUMP_TYPE_FULL, &ExInfo, NULL, NULL );
					if (bOK)
					{
						swprintf( szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath );
						szResult = szScratch;
                        retval = EXCEPTION_EXECUTE_HANDLER;
					}
					else
					{
						swprintf( szScratch, sizeof(szScratch),L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() );
                        szResult = szScratch;
					}
                    CloseHandle(hFile);

					WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
					swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);
					
					//PrintError(_T("%s"), csOutMessage);
                    //MessageBoxW( NULL, csOutMessage, m_szAppName , MB_OK );
                    qDebug() << "Dump Crash file ...";
				}
				else
				{
					swprintf( szScratch, sizeof(szScratch),L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() );
					szResult = szScratch;
				}
			}

		}
		else
		{
			szResult = L"DBGHELP.DLL too old";
		}
	}
	else
	{
		szResult = L"DBGHELP.DLL not found";
	}

	if (szResult)
	{
		//PrintDebug(_T("[MiniDumper] Mini Dump result:[%s]"),szResult);		
	}

	return retval;
}

在main.cpp中添加如下代码:

    MiniDumper dump;

 程序意外退出时,在debug或者release下生成dump文件,如下图所示:

双击dmp文件,用vs打开。点击下图中红色箭头指向的“使用 仅限本机进行调试”,即可定位到出错的地方。

 

 

 

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值