wxSEHReport renamed to wxCrashReport enhanced and debugged; seems to work
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@21936 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
335991afa5
commit
50bea10032
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/msw/seh.h
|
||||
// Name: wx/msw/crashrpt.h
|
||||
// Purpose: helpers for the structured exception handling (SEH) under Win32
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
@ -17,10 +17,32 @@
|
||||
#if wxUSE_ON_FATAL_EXCEPTION
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSEHReport: this class is used as a namespace for the SEH-related functions
|
||||
// report generation flags
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct WXDLLIMPEXP_BASE wxSEHReport
|
||||
enum
|
||||
{
|
||||
// we always report where the crash occured
|
||||
wxCRASH_REPORT_LOCATION = 0,
|
||||
|
||||
// if this flag is given, the call stack is dumped
|
||||
wxCRASH_REPORT_STACK = 1,
|
||||
|
||||
// if this flag is given, the values of the local variables are dumped
|
||||
wxCRASH_REPORT_LOCALS = 2,
|
||||
|
||||
// if this flag is given, the values of all global variables are dumped
|
||||
//
|
||||
// WARNING: this may take a very long time and generate megabytes of output
|
||||
// in a big program, this is why it is off by default
|
||||
wxCRASH_REPORT_GLOBALS = 4
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxCrashReport: this class is used to create crash reports
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct WXDLLIMPEXP_BASE wxCrashReport
|
||||
{
|
||||
// set the name of the file to which the report is written, it is
|
||||
// constructed from the .exe name by default
|
||||
@ -31,7 +53,9 @@ struct WXDLLIMPEXP_BASE wxSEHReport
|
||||
|
||||
// write the exception report to the file, return true if it could be done
|
||||
// or false otherwise
|
||||
static bool Generate();
|
||||
static bool Generate(int flags = wxCRASH_REPORT_LOCATION |
|
||||
wxCRASH_REPORT_STACK |
|
||||
wxCRASH_REPORT_LOCALS);
|
||||
};
|
||||
|
||||
#endif // wxUSE_ON_FATAL_EXCEPTION
|
1116
src/msw/crashrpt.cpp
Normal file
1116
src/msw/crashrpt.cpp
Normal file
File diff suppressed because it is too large
Load Diff
585
src/msw/seh.cpp
585
src/msw/seh.cpp
@ -1,585 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: msw/seh.cpp
|
||||
// Purpose: helpers for structured exception handling (SEH)
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified by:
|
||||
// Created: 13.07.03
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The code in this file is heavily based on Matt Pietrek's column from
|
||||
the 2002 issue of MSDN Magazine.
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// For compilers that support precompilation, includes "wx.h".
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#if wxUSE_ON_FATAL_EXCEPTION
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/datetime.h"
|
||||
#include "wx/dynload.h"
|
||||
|
||||
#include "wx/msw/seh.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include "wx/msw/private.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// types of imagehlp.h functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
|
||||
typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
|
||||
typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME,
|
||||
LPVOID, PREAD_PROCESS_MEMORY_ROUTINE,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE,
|
||||
PGET_MODULE_BASE_ROUTINE,
|
||||
PTRANSLATE_ADDRESS_ROUTINE);
|
||||
typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
|
||||
typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD);
|
||||
typedef DWORD (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD);
|
||||
typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD,
|
||||
PDWORD, PIMAGEHLP_LINE);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// the real crash report generator
|
||||
class wxSEHReportImpl
|
||||
{
|
||||
public:
|
||||
wxSEHReportImpl(const wxChar *filename);
|
||||
|
||||
bool Generate();
|
||||
|
||||
~wxSEHReportImpl()
|
||||
{
|
||||
if ( m_hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
::CloseHandle(m_hFile);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// formatted output to m_hFile
|
||||
void Output(const wxChar *format, ...);
|
||||
|
||||
// translate exception code to its symbolic name
|
||||
static wxString GetExceptionString(DWORD dwCode);
|
||||
|
||||
// load all the functions we need from dbghelp.dll, return true if all ok
|
||||
bool ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp);
|
||||
|
||||
// map address to module (and also section:offset), retunr true if ok
|
||||
static bool GetLogicalAddress(PVOID addr,
|
||||
PTSTR szModule,
|
||||
DWORD len,
|
||||
DWORD& section,
|
||||
DWORD& offset);
|
||||
|
||||
|
||||
// show the general information about exception which should be always
|
||||
// available
|
||||
bool OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pCtx);
|
||||
|
||||
// output the call stack (pCtx may be modified, make copy before call!)
|
||||
void OutputStack(CONTEXT *pCtx);
|
||||
|
||||
|
||||
// the handle of the report file
|
||||
HANDLE m_hFile;
|
||||
|
||||
// dynamically loaded dbghelp.dll functions
|
||||
#define DECLARE_SYM_FUNCTION(func) func ## _t func
|
||||
|
||||
DECLARE_SYM_FUNCTION(SymSetOptions);
|
||||
DECLARE_SYM_FUNCTION(SymInitialize);
|
||||
DECLARE_SYM_FUNCTION(StackWalk);
|
||||
DECLARE_SYM_FUNCTION(SymFromAddr);
|
||||
DECLARE_SYM_FUNCTION(SymFunctionTableAccess);
|
||||
DECLARE_SYM_FUNCTION(SymGetModuleBase);
|
||||
DECLARE_SYM_FUNCTION(SymGetLineFromAddr);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// globals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// global pointer to exception information, only valid inside OnFatalException
|
||||
extern WXDLLIMPEXP_BASE EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
|
||||
|
||||
|
||||
// flag telling us whether the application wants to handle exceptions at all
|
||||
static bool gs_handleExceptions = false;
|
||||
|
||||
// the file name where the report about exception is written
|
||||
static wxChar gs_reportFilename[MAX_PATH];
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSEHReport
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxSEHReportImpl::wxSEHReportImpl(const wxChar *filename)
|
||||
{
|
||||
m_hFile = ::CreateFile
|
||||
(
|
||||
filename,
|
||||
GENERIC_WRITE,
|
||||
0, // no sharing
|
||||
NULL, // default security
|
||||
CREATE_ALWAYS,
|
||||
FILE_FLAG_WRITE_THROUGH,
|
||||
NULL // no template file
|
||||
);
|
||||
}
|
||||
|
||||
void wxSEHReportImpl::Output(const wxChar *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
|
||||
DWORD cbWritten;
|
||||
|
||||
wxString s = wxString::FormatV(format, argptr);
|
||||
::WriteFile(m_hFile, s, s.length() * sizeof(wxChar), &cbWritten, 0);
|
||||
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
bool
|
||||
wxSEHReportImpl::GetLogicalAddress(PVOID addr,
|
||||
PTSTR szModule,
|
||||
DWORD len,
|
||||
DWORD& section,
|
||||
DWORD& offset)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
||||
if ( !::VirtualQuery(addr, &mbi, sizeof(mbi)) )
|
||||
return false;
|
||||
|
||||
DWORD hMod = (DWORD)mbi.AllocationBase;
|
||||
|
||||
if ( !::GetModuleFileName((HMODULE)hMod, szModule, len) )
|
||||
return false;
|
||||
|
||||
// Point to the DOS header in memory
|
||||
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
|
||||
|
||||
// From the DOS header, find the NT (PE) header
|
||||
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
|
||||
|
||||
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION( pNtHdr );
|
||||
|
||||
DWORD rva = (DWORD)addr - hMod; // RVA is offset from module load address
|
||||
|
||||
// Iterate through the section table, looking for the one that encompasses
|
||||
// the linear address.
|
||||
const DWORD nSections = pNtHdr->FileHeader.NumberOfSections;
|
||||
for ( DWORD i = 0; i < nSections; i++, pSection++ )
|
||||
{
|
||||
DWORD sectionStart = pSection->VirtualAddress;
|
||||
DWORD sectionEnd = sectionStart
|
||||
+ max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
|
||||
|
||||
// Is the address in this section?
|
||||
if ( (rva >= sectionStart) && (rva <= sectionEnd) )
|
||||
{
|
||||
// Yes, address is in the section. Calculate section and offset,
|
||||
// and store in the "section" & "offset" params, which were
|
||||
// passed by reference.
|
||||
section = i + 1;
|
||||
offset = rva - sectionStart;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// failed to map to logical address...
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
wxSEHReportImpl::OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord,
|
||||
CONTEXT *pCtx)
|
||||
{
|
||||
// First print information about the type of fault
|
||||
const DWORD dwCode = pExceptionRecord->ExceptionCode;
|
||||
Output(_T("Exception code: %s (%#08x)\r\n"),
|
||||
GetExceptionString(dwCode).c_str(), dwCode);
|
||||
|
||||
// Now print information about where the fault occured
|
||||
TCHAR szFaultingModule[MAX_PATH];
|
||||
DWORD section,
|
||||
offset;
|
||||
void * const pExceptionAddress = pExceptionRecord->ExceptionAddress;
|
||||
if ( !GetLogicalAddress(pExceptionAddress,
|
||||
szFaultingModule,
|
||||
WXSIZEOF(szFaultingModule),
|
||||
section, offset) )
|
||||
{
|
||||
section =
|
||||
offset = 0;
|
||||
|
||||
wxStrcpy(szFaultingModule, _T("<< unknown >>"));
|
||||
}
|
||||
|
||||
Output(_T("Fault address: %08x %02x:%08x %s\r\n"),
|
||||
pExceptionAddress, section, offset, szFaultingModule);
|
||||
|
||||
// Show the registers
|
||||
#ifdef _M_IX86
|
||||
Output( _T("\r\nRegisters:\r\n") );
|
||||
|
||||
Output(_T("EAX: %08x EBX: %08x ECX: %08x EDX: %08x ESI: %08x EDI: %08x\r\n"),
|
||||
pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, pCtx->Esi, pCtx->Edi);
|
||||
|
||||
Output(_T("CS:EIP: %04x:%08x SS:ESP: %04x:%08x EBP: %08x\r\n"),
|
||||
pCtx->SegCs, pCtx->Eip, pCtx->SegSs, pCtx->Esp, pCtx->Ebp );
|
||||
Output(_T("DS: %04x ES: %04x FS: %04x GS: %04x\r\n"),
|
||||
pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
|
||||
Output(_T("Flags: %08x\r\n"), pCtx->EFlags );
|
||||
#endif // _M_IX86
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxSEHReportImpl::OutputStack(CONTEXT *pCtx)
|
||||
{
|
||||
Output(_T("\r\nCall stack:\r\n"));
|
||||
|
||||
Output(_T("Address Frame Function SourceFile\r\n"));
|
||||
|
||||
DWORD dwMachineType = 0;
|
||||
|
||||
STACKFRAME sf;
|
||||
wxZeroMemory(sf);
|
||||
|
||||
#ifdef _M_IX86
|
||||
// Initialize the STACKFRAME structure for the first call. This is only
|
||||
// necessary for Intel CPUs, and isn't mentioned in the documentation.
|
||||
sf.AddrPC.Offset = pCtx->Eip;
|
||||
sf.AddrPC.Mode = AddrModeFlat;
|
||||
sf.AddrStack.Offset = pCtx->Esp;
|
||||
sf.AddrStack.Mode = AddrModeFlat;
|
||||
sf.AddrFrame.Offset = pCtx->Ebp;
|
||||
sf.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
dwMachineType = IMAGE_FILE_MACHINE_I386;
|
||||
#endif // _M_IX86
|
||||
|
||||
const HANDLE hProcess = GetCurrentProcess();
|
||||
const HANDLE hThread = GetCurrentThread();
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
// Get the next stack frame
|
||||
if ( !StackWalk(dwMachineType,
|
||||
hProcess,
|
||||
hThread,
|
||||
&sf,
|
||||
pCtx,
|
||||
0,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
0) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Basic sanity check to make sure the frame is OK.
|
||||
if ( !sf.AddrFrame.Offset )
|
||||
break;
|
||||
|
||||
Output(_T("%08x %08x "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
|
||||
|
||||
// Get the name of the function for this stack frame entry
|
||||
BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + 1024 ];
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
|
||||
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
|
||||
pSymbol->MaxNameLen = 1024;
|
||||
DWORD64 symDisplacement = 0; // Displacement of the input address,
|
||||
// relative to the start of the symbol
|
||||
|
||||
if ( SymFromAddr(hProcess, sf.AddrPC.Offset,
|
||||
&symDisplacement,pSymbol) )
|
||||
{
|
||||
Output(_T("%hs() + %#08I64x"), pSymbol->Name, symDisplacement);
|
||||
}
|
||||
else // No symbol found. Print out the logical address instead.
|
||||
{
|
||||
TCHAR szModule[MAX_PATH];
|
||||
DWORD section,
|
||||
offset;
|
||||
|
||||
if ( !GetLogicalAddress((PVOID)sf.AddrPC.Offset,
|
||||
szModule, sizeof(szModule),
|
||||
section, offset) )
|
||||
{
|
||||
szModule[0] = _T('\0');
|
||||
section =
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
Output(_T("%04x:%08x %s"), section, offset, szModule);
|
||||
}
|
||||
|
||||
// Get the source line for this stack frame entry
|
||||
IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
|
||||
DWORD dwLineDisplacement;
|
||||
if ( SymGetLineFromAddr(hProcess, sf.AddrPC.Offset,
|
||||
&dwLineDisplacement, &lineInfo ))
|
||||
{
|
||||
Output(_T(" %s line %u"), lineInfo.FileName, lineInfo.LineNumber);
|
||||
}
|
||||
|
||||
Output(_T("\r\n"));
|
||||
}
|
||||
}
|
||||
|
||||
bool wxSEHReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
|
||||
{
|
||||
#define LOAD_SYM_FUNCTION(name) \
|
||||
name = (name ## _t) dllDbgHelp.GetSymbol(#name); \
|
||||
if ( !name ) \
|
||||
{ \
|
||||
Output(_T("\r\nFunction ") __XFILE__(#name) \
|
||||
_T("() not found.\r\n")); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
LOAD_SYM_FUNCTION(SymSetOptions);
|
||||
LOAD_SYM_FUNCTION(SymInitialize);
|
||||
LOAD_SYM_FUNCTION(StackWalk);
|
||||
LOAD_SYM_FUNCTION(SymFromAddr);
|
||||
LOAD_SYM_FUNCTION(SymFunctionTableAccess);
|
||||
LOAD_SYM_FUNCTION(SymGetModuleBase);
|
||||
LOAD_SYM_FUNCTION(SymGetLineFromAddr);
|
||||
|
||||
#undef LOAD_SYM_FUNCTION
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxSEHReportImpl::Generate()
|
||||
{
|
||||
if ( m_hFile == INVALID_HANDLE_VALUE )
|
||||
return false;
|
||||
|
||||
PEXCEPTION_RECORD pExceptionRecord = wxGlobalSEInformation->ExceptionRecord;
|
||||
PCONTEXT pCtx = wxGlobalSEInformation->ContextRecord;
|
||||
|
||||
if ( !OutputBasicContext(pExceptionRecord, pCtx) )
|
||||
return false;
|
||||
|
||||
// for everything else we need dbghelp.dll
|
||||
wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
|
||||
if ( dllDbgHelp.IsLoaded() )
|
||||
{
|
||||
if ( ResolveSymFunctions(dllDbgHelp) )
|
||||
{
|
||||
SymSetOptions(SYMOPT_DEFERRED_LOADS);
|
||||
|
||||
// Initialize DbgHelp
|
||||
if ( SymInitialize(GetCurrentProcess(), NULL, TRUE /* invade */) )
|
||||
{
|
||||
CONTEXT ctxCopy = *pCtx;
|
||||
|
||||
OutputStack(&ctxCopy);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(_T("Please update your dbghelp.dll version, "
|
||||
"at least version 6.0 is needed!\r\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(_T("Please install dbghelp.dll available free of charge ")
|
||||
_T("from Microsoft to get more detailed crash information!"));
|
||||
}
|
||||
|
||||
Output(_T("\r\nLatest dbghelp.dll is available at "
|
||||
"http://www.microsoft.com/whdc/ddk/debugging/\r\n"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
wxString wxSEHReportImpl::GetExceptionString(DWORD dwCode)
|
||||
{
|
||||
wxString s;
|
||||
|
||||
#define CASE_EXCEPTION( x ) case EXCEPTION_##x: s = _T(#x); break
|
||||
|
||||
switch ( dwCode )
|
||||
{
|
||||
CASE_EXCEPTION(ACCESS_VIOLATION);
|
||||
CASE_EXCEPTION(DATATYPE_MISALIGNMENT);
|
||||
CASE_EXCEPTION(BREAKPOINT);
|
||||
CASE_EXCEPTION(SINGLE_STEP);
|
||||
CASE_EXCEPTION(ARRAY_BOUNDS_EXCEEDED);
|
||||
CASE_EXCEPTION(FLT_DENORMAL_OPERAND);
|
||||
CASE_EXCEPTION(FLT_DIVIDE_BY_ZERO);
|
||||
CASE_EXCEPTION(FLT_INEXACT_RESULT);
|
||||
CASE_EXCEPTION(FLT_INVALID_OPERATION);
|
||||
CASE_EXCEPTION(FLT_OVERFLOW);
|
||||
CASE_EXCEPTION(FLT_STACK_CHECK);
|
||||
CASE_EXCEPTION(FLT_UNDERFLOW);
|
||||
CASE_EXCEPTION(INT_DIVIDE_BY_ZERO);
|
||||
CASE_EXCEPTION(INT_OVERFLOW);
|
||||
CASE_EXCEPTION(PRIV_INSTRUCTION);
|
||||
CASE_EXCEPTION(IN_PAGE_ERROR);
|
||||
CASE_EXCEPTION(ILLEGAL_INSTRUCTION);
|
||||
CASE_EXCEPTION(NONCONTINUABLE_EXCEPTION);
|
||||
CASE_EXCEPTION(STACK_OVERFLOW);
|
||||
CASE_EXCEPTION(INVALID_DISPOSITION);
|
||||
CASE_EXCEPTION(GUARD_PAGE);
|
||||
CASE_EXCEPTION(INVALID_HANDLE);
|
||||
|
||||
default:
|
||||
// unknown exception, ask NTDLL for the name
|
||||
if ( !::FormatMessage
|
||||
(
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_HMODULE,
|
||||
::GetModuleHandle(_T("NTDLL.DLL")),
|
||||
dwCode,
|
||||
0,
|
||||
wxStringBuffer(s, 1024),
|
||||
1024,
|
||||
0
|
||||
) )
|
||||
{
|
||||
s = _T("UNKNOWN_EXCEPTION");
|
||||
}
|
||||
}
|
||||
|
||||
#undef CASE_EXCEPTION
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSEHReport
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* static */
|
||||
void wxSEHReport::SetFileName(const wxChar *filename)
|
||||
{
|
||||
wxStrncpy(gs_reportFilename, filename, WXSIZEOF(gs_reportFilename) - 1);
|
||||
gs_reportFilename[WXSIZEOF(gs_reportFilename) - 1] = _T('\0');
|
||||
}
|
||||
|
||||
/* static */
|
||||
const wxChar *wxSEHReport::GetFileName()
|
||||
{
|
||||
return gs_reportFilename;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool wxSEHReport::Generate()
|
||||
{
|
||||
wxSEHReportImpl impl(gs_reportFilename);
|
||||
|
||||
return impl.Generate();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxApp::OnFatalException() support
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxHandleFatalExceptions(bool doit)
|
||||
{
|
||||
// assume this can only be called from the main thread
|
||||
gs_handleExceptions = doit;
|
||||
|
||||
if ( doit )
|
||||
{
|
||||
// try to find a place where we can put out report file later
|
||||
if ( !::GetTempPath
|
||||
(
|
||||
WXSIZEOF(gs_reportFilename),
|
||||
gs_reportFilename
|
||||
) )
|
||||
{
|
||||
wxLogLastError(_T("GetTempPath"));
|
||||
|
||||
// when all else fails...
|
||||
wxStrcpy(gs_reportFilename, _T("c:\\"));
|
||||
}
|
||||
|
||||
// use PID and date to make the report file name more unique
|
||||
wxString fname = wxString::Format
|
||||
(
|
||||
_T("%s_%s_%lu.rpt"),
|
||||
wxTheApp ? wxTheApp->GetAppName().c_str()
|
||||
: _T("wxwindows"),
|
||||
wxDateTime::Now().Format(_T("%Y%m%d")).c_str(),
|
||||
::GetCurrentProcessId()
|
||||
);
|
||||
|
||||
wxStrncat(gs_reportFilename, fname,
|
||||
WXSIZEOF(gs_reportFilename) - strlen(gs_reportFilename) - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
|
||||
{
|
||||
if ( gs_handleExceptions && wxTheApp )
|
||||
{
|
||||
// store the pointer to exception info
|
||||
wxGlobalSEInformation = pExcPtrs;
|
||||
|
||||
// give the user a chance to do something special about this
|
||||
wxTheApp->OnFatalException();
|
||||
|
||||
wxGlobalSEInformation = NULL;
|
||||
|
||||
// this will execute our handler and terminate the process
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#else // !wxUSE_ON_FATAL_EXCEPTION
|
||||
|
||||
bool wxHandleFatalExceptions(bool WXUNUSED(doit))
|
||||
{
|
||||
wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
|
||||
|
Loading…
Reference in New Issue
Block a user