exceptionreport.cpp

来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 703 行 · 第 1/2 页

CPP
703
字号
// FileZilla - a Windows ftp client

// Copyright (C) 2004 - Tim Kosse <tim.kosse@gmx.de>

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// OptionsTypePage.cpp: Implementierungsdatei
//

#include "stdafx.h"
#include <dbghelp.h>
#include "ExceptionReport.h"
#include "..\version.h"
#include "ProcessorInfo.h"
#include "WindowsVersion.h"
#include "mailmsg.h"
#include "Tlhelp32.h"

typedef BOOL
(_stdcall *tSymFromAddr)(
	IN  HANDLE			hProcess,
	IN  DWORD64			Address,
	OUT PDWORD64		Displacement,
	IN OUT PSYMBOL_INFO	Symbol
	);

typedef DWORD
(_stdcall *tSymGetOptions)(
	);

typedef DWORD
(_stdcall *tSymSetOptions)(
	IN DWORD   SymOptions
	);

typedef BOOL
(_stdcall *tSymCleanup)(
	IN HANDLE hProcess
	);

typedef BOOL
(_stdcall *tSymInitialize)(
	IN HANDLE	hProcess,
	IN PSTR		UserSearchPath,
	IN BOOL		fInvadeProcess
	);

typedef BOOL
(_stdcall *tSymGetLineFromAddr)(
	IN  HANDLE				hProcess,
	IN  DWORD				dwAddr,
	OUT PDWORD				pdwDisplacement,
	OUT PIMAGEHLP_LINE		Line
	);

typedef BOOL
(_stdcall *tStackWalk)(
	DWORD							MachineType,
	HANDLE							hProcess,
	HANDLE							hThread,
	LPSTACKFRAME					StackFrame,
	PVOID							ContextRecord,
	PREAD_PROCESS_MEMORY_ROUTINE	ReadMemoryRoutine,
	PFUNCTION_TABLE_ACCESS_ROUTINE	FunctionTableAccessRoutine,
	PGET_MODULE_BASE_ROUTINE		GetModuleBaseRoutine,
	PTRANSLATE_ADDRESS_ROUTINE		TranslateAddress
	);

typedef PVOID
(_stdcall *tSymFunctionTableAccess)(
	HANDLE  hProcess,
	DWORD   AddrBase
	);

typedef DWORD
(_stdcall *tSymGetModuleBase)(
	IN  HANDLE			  hProcess,
	IN  DWORD			   dwAddr
	);

typedef BOOL
(_stdcall *tMiniDumpWriteDump)(
	HANDLE hProcess,
	DWORD ProcessId,
	HANDLE hFile,
	MINIDUMP_TYPE DumpType,
	PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
	PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
	PMINIDUMP_CALLBACK_INFORMATION CallbackParam
	);

static tSymCleanup				pSymCleanup;
static tSymInitialize			pSymInitialize;
static tSymGetOptions			pSymGetOptions;
static tSymSetOptions			pSymSetOptions;
static tSymGetLineFromAddr		pSymGetLineFromAddr;
static tSymFromAddr				pSymFromAddr;
static tStackWalk				pStackWalk;
static tSymFunctionTableAccess	pSymFunctionTableAccess;
static tSymGetModuleBase		pSymGetModuleBase;
static tMiniDumpWriteDump		pMiniDumpWriteDump;

// Global class instance
static CExceptionReport ExceptionReport;

LPTOP_LEVEL_EXCEPTION_FILTER CExceptionReport::m_previousExceptionFilter;
TCHAR CExceptionReport::m_pLogFileName[MAX_PATH];
HANDLE CExceptionReport::m_hReportFile;
TCHAR CExceptionReport::m_pDmpFileName[MAX_PATH];
HANDLE CExceptionReport::m_hDumpFile;
BOOL CExceptionReport::m_bFirstRun;

CExceptionReport::CExceptionReport()
{
	m_bFirstRun = TRUE;

	m_previousExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);

	// Retrieve report/dump filenames
	GetModuleFileName(0, m_pLogFileName, MAX_PATH);

	// Look for the '.' before the "EXE" extension.  Replace the extension
	// with "RPT"
	LPTSTR p = _tcsrchr(m_pLogFileName, _T('.'));
	if (p)
	{
		p++;
		*p = 0;
		_tcscpy(m_pDmpFileName, m_pLogFileName);
		_tcscpy(p, _T("rpt"));
		_tcscat(m_pDmpFileName, _T("dmp"));
	}
}

CExceptionReport::~CExceptionReport()
{
	SetUnhandledExceptionFilter(m_previousExceptionFilter);
}

LONG WINAPI CExceptionReport::UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
	if (!m_bFirstRun)
	{
		// Don't generate exception report twice
		if (m_previousExceptionFilter)
			return m_previousExceptionFilter(pExceptionInfo);
		else
			return EXCEPTION_CONTINUE_SEARCH;
	}
	else
		m_bFirstRun = FALSE;

	// Suspend all threads to freeze the current state
	SuspendThreads();
	
	HMODULE hDll = LoadLibrary(_T("dbghelp.dll"));
	if (!hDll)
	{
		if (m_previousExceptionFilter)
			return m_previousExceptionFilter(pExceptionInfo);
		else
			return EXCEPTION_CONTINUE_SEARCH;
	}

	pSymCleanup				= (tSymCleanup)GetProcAddress(hDll, "SymCleanup");
	pSymInitialize			= (tSymInitialize)GetProcAddress(hDll, "SymInitialize");
	pSymGetOptions			= (tSymGetOptions)GetProcAddress(hDll, "SymGetOptions");
	pSymSetOptions			= (tSymSetOptions)GetProcAddress(hDll, "SymSetOptions");
	pSymGetLineFromAddr		= (tSymGetLineFromAddr)GetProcAddress(hDll, "SymGetLineFromAddr");
	pSymFromAddr			= (tSymFromAddr)GetProcAddress(hDll, "SymFromAddr");
	pStackWalk				= (tStackWalk)GetProcAddress(hDll, "StackWalk");
	pSymFunctionTableAccess	= (tSymFunctionTableAccess)GetProcAddress(hDll, "SymFunctionTableAccess");
	pSymGetModuleBase		= (tSymGetModuleBase)GetProcAddress(hDll, "SymGetModuleBase");
	pMiniDumpWriteDump		= (tMiniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump");

	if (!pSymCleanup			||
		!pSymInitialize			||
		!pSymGetOptions			||
		!pSymSetOptions			||
		!pSymGetLineFromAddr	||
		!pSymFromAddr			||
		!pStackWalk				||
		!pSymFunctionTableAccess||
		!pSymGetModuleBase		||
		!pMiniDumpWriteDump)
	{
		FreeLibrary(hDll);
		if (m_previousExceptionFilter)
			return m_previousExceptionFilter(pExceptionInfo);
		else
			return EXCEPTION_CONTINUE_SEARCH;
	}

	if (::MessageBox(NULL,
_T("An unhandled exception has occurred in FileZilla\r\n\
FileZilla has to be closed.\r\n\r\n\
Would you like to generate an exception report?\r\n\
The report contains all neccessary information about the exception,\r\n\
including a call stack with function parameters and local variables.\r\n\r\n\
If you're using the latest version of FileZilla, please send the generated exception record to the following mail address: Tim.Kosse@gmx.de\r\n\
The report will be analyzed and the reason for this exception will be fixed in the next version of FileZilla.\r\n\r\n\
Please note: It may be possible - though unlikely - that the exception report may contain personal and or confidential information. All exception reports will be processed higly confidential and solely to analyze the crash. The reports will be deleted immediately after processing.\r\n"),
		_T("FileZilla - Unhandled exception"), MB_APPLMODAL | MB_YESNO | MB_ICONSTOP)==IDYES)
	{
		m_hReportFile = CreateFile(m_pLogFileName, GENERIC_WRITE,FILE_SHARE_READ,
								   0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
	
		m_hDumpFile = CreateFile(m_pDmpFileName, GENERIC_WRITE, FILE_SHARE_READ,
								 0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,	0);
	
		if (m_hReportFile == INVALID_HANDLE_VALUE)
		{
			TCHAR tmp[MAX_PATH];
			_tcscpy(tmp, m_pLogFileName);
			TCHAR *pos=_tcsrchr(tmp, '\\');
			if (pos)
			{
				pos++;
				_stprintf(m_pLogFileName, _T("c:\\%s"), pos);
			}
			else
				_stprintf(m_pLogFileName, _T("c:\\%s"), tmp);
		
			m_hReportFile = CreateFile(m_pLogFileName, GENERIC_WRITE,FILE_SHARE_READ,
									   0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
		}
		if (m_hDumpFile == INVALID_HANDLE_VALUE)
		{
			TCHAR tmp[MAX_PATH];
			_tcscpy(tmp, m_pDmpFileName);
			TCHAR *pos=_tcsrchr(tmp, '\\');
			if (pos)
			{
				pos++;
				_stprintf(m_pDmpFileName, _T("c:\\%s"), pos);
			}
			else
				_stprintf(m_pDmpFileName, _T("c:\\%s"), tmp);
		
			m_hDumpFile = CreateFile(m_pDmpFileName, GENERIC_WRITE, FILE_SHARE_READ,
									 0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,	0);
		}

		int nError=0;
		if (m_hReportFile == INVALID_HANDLE_VALUE && INVALID_HANDLE_VALUE)
			nError = GetLastError();
		else
		{
#ifdef TRY
			TRY
#endif
			{
				if (m_hReportFile != INVALID_HANDLE_VALUE)
					CreateReport(pExceptionInfo);
	
				CloseHandle(m_hReportFile);
			}
#ifdef TRY
			CATCH_ALL(e);
			{
				nError = GetLastError();
				CloseHandle(m_hReportFile);
			}
			END_CATCH_ALL

			TRY
#endif
			{
				if (m_hDumpFile != INVALID_HANDLE_VALUE)
					writeMiniDump(pExceptionInfo);

				CloseHandle(m_hDumpFile);
				nError = 0;
			}
#ifdef TRY
			CATCH_ALL(e);
			{
				CloseHandle(m_hDumpFile);
			}
			END_CATCH_ALL
#endif
		}

		if (nError)
		{
		
			TCHAR tmp[1000];
			_stprintf(tmp, _T("Unable to create exception report, error code %d."), nError);
			MessageBox(0, tmp, _T("FileZilla - Unhandled eception"), MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
		}
		else
		{
			sendMail();

			TCHAR tmp[1000];
			_stprintf(tmp, _T("The exception report has been saved to \"%s\" and \"%s\".\n\
Please make sure that you are using the latest version of FileZilla.\n\
You can download the latest version from http://sourceforge.net/projects/filezilla/.\n\
If you do use the latest version, please send the exception report to Tim.Kosse@gmx.de along with a brief explanation what you did before FileZilla crashed."), m_pLogFileName, m_pDmpFileName);
			MessageBox(0, tmp, _T("FileZilla - Unhandled eception"), MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);

			FreeLibrary(hDll);
			return EXCEPTION_CONTINUE_SEARCH;
		}
	}
	FreeLibrary(hDll);
	if (m_previousExceptionFilter)
		return m_previousExceptionFilter(pExceptionInfo);
	else
		return EXCEPTION_CONTINUE_SEARCH;

}

void CExceptionReport::CreateReport(PEXCEPTION_POINTERS pExceptionInfo)
{
	// Start out with a banner
	AddToReport("Exception report created by ");
	AddToReport(GetVersionString());
	AddToReport("\r\n===================================================\r\n\r\n");
	AddToReport("System details:\r\n");
	AddToReport("---------------\r\n\r\nOperating System:      ");
	
	TCHAR buffer[200];
	if (DisplaySystemVersion(buffer))
	{
		AddToReport(buffer);
		AddToReport("\r\n");
	}
	else
		AddToReport("Could not get OS version\r\n");
	
	CProcessorInfo pi;
	CMemoryInfo mi;
	AddToReport("Processor Information: ");
	AddToReport(pi.GetProcessorName());
	AddToReport("\r\nMemory Information:    ");
	AddToReport(mi.GetMemoryInfo());
	
	PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?