mirror of https://github.com/roytam1/kmeleon.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
579 lines
19 KiB
579 lines
19 KiB
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
|
|
/* |
|
* Copyright (C) 2005 Ulf Erikson <ulferikson@fastmail.fm> |
|
* |
|
* 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, 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. |
|
*/ |
|
|
|
/* |
|
* Based on the MiniDump demo by Vladimir Sedach |
|
* http://www.codeproject.com/tools/minidump.asp |
|
*/ |
|
|
|
#include <windows.h> |
|
#include <tlhelp32.h> |
|
|
|
#define KMELEON_PLUGIN_EXPORTS |
|
#include "..\kmeleon_plugin.h" |
|
|
|
#define PLUGIN_NAME "Crash Report Plugin" |
|
#define NO_OPTIONS "This plugin has no user configurable options." |
|
|
|
#define _T(x) (x) |
|
|
|
#define PREFERENCE_CRASHFILE _T("kmeleon.plugins.crash.reportFile") |
|
|
|
PCHAR Str; |
|
PCHAR Dump_Path; |
|
PCHAR TmpStr; |
|
|
|
static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pException); |
|
|
|
typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); |
|
typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); |
|
typedef BOOL (WINAPI * MODULE32_NEXT)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); |
|
|
|
CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; |
|
MODULE32_FIRST Module32First_; |
|
MODULE32_NEXT Module32Next_; |
|
|
|
#define DUMP_SIZE_MAX (8*1024) |
|
#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - (2*1024)) / (MAX_PATH + 40)) |
|
#define NL "\r\n" |
|
|
|
BOOL APIENTRY DllMain ( |
|
HANDLE hModule, |
|
DWORD ul_reason_for_call, |
|
LPVOID lpReserved) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
LRESULT CALLBACK WndProc ( |
|
HWND hWnd, UINT message, |
|
WPARAM wParam, |
|
LPARAM lParam); |
|
BOOL CALLBACK DlgProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); |
|
|
|
void * KMeleonWndProc; |
|
|
|
INT Load(); |
|
void Config(HWND parent); |
|
void Exit(); |
|
LONG DoMessage(LPCTSTR to, LPCTSTR from, LPCTSTR subject, LONG data1, LONG data2); |
|
|
|
kmeleonPlugin kPlugin = |
|
{ |
|
KMEL_PLUGIN_VER, |
|
PLUGIN_NAME, |
|
DoMessage |
|
}; |
|
kmeleonFunctions *kFuncs; |
|
|
|
#define lenof(a) (sizeof(a) / sizeof((a)[0])) |
|
|
|
// Global variables initialization |
|
BOOL InitGlobals() |
|
{ |
|
const char *dllname[] = { "kernel32.dll", "tlhelp32.dll" }; |
|
HMODULE hModule; |
|
int i; |
|
|
|
for ( i = 0; i < lenof( dllname ); ++ i ) { |
|
hModule = GetModuleHandle(dllname[i]); |
|
if (hModule) { |
|
CreateToolhelp32Snapshot_ = |
|
(CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hModule, |
|
"CreateToolhelp32Snapshot"); |
|
Module32First_ = (MODULE32_FIRST)GetProcAddress(hModule, |
|
"Module32First"); |
|
Module32Next_ = (MODULE32_NEXT)GetProcAddress(hModule, |
|
"Module32Next"); |
|
|
|
if (CreateToolhelp32Snapshot_ && Module32First_ && Module32Next_) |
|
break; |
|
|
|
hModule = NULL; |
|
} |
|
} |
|
|
|
Str = (CHAR*) malloc(DUMP_SIZE_MAX * sizeof(CHAR)); |
|
if (Str) |
|
Str[0] = '\0'; |
|
Dump_Path = (CHAR*) malloc(MAX_PATH * sizeof(CHAR)); |
|
if (Dump_Path) { |
|
CHAR *cptr = NULL; |
|
|
|
kFuncs->GetPreference(PREF_STRING, PREFERENCE_CRASHFILE, Dump_Path, _T("")); |
|
|
|
if (*Dump_Path) { |
|
cptr = strrchr(Dump_Path, '\\'); |
|
if (cptr && !*(cptr+1)) |
|
lstrcat(cptr, "k-meleon.crash"); |
|
} |
|
else { |
|
GetModuleFileName(NULL, Dump_Path, MAX_PATH); |
|
cptr = strrchr(Dump_Path, '.'); |
|
lstrcpy(cptr ? cptr+1 : Dump_Path + lstrlen(Dump_Path), cptr ? "crash" : ".crash"); |
|
} |
|
} |
|
TmpStr = (CHAR*) malloc(MAX_PATH * sizeof(CHAR)); |
|
if (TmpStr) |
|
TmpStr[0] = '\0'; |
|
|
|
return hModule != NULL; |
|
} |
|
|
|
INT Load() |
|
{ |
|
kFuncs = kPlugin.kFuncs; |
|
if (InitGlobals()) |
|
SetUnhandledExceptionFilter(CrashHandlerExceptionFilter); |
|
return TRUE; |
|
} |
|
|
|
void Config(HWND parent) |
|
{ |
|
MessageBox(parent, NO_OPTIONS, PLUGIN_NAME, 0); |
|
} |
|
|
|
void Exit() |
|
{ |
|
SetUnhandledExceptionFilter(NULL); |
|
} |
|
|
|
LONG DoMessage(LPCTSTR to, LPCTSTR from, LPCTSTR subject, LONG data1, LONG data2) |
|
{ |
|
if (to[0] == '*' || stricmp(to, kPlugin.dllname) == 0) { |
|
if (stricmp(subject, "Load") == 0) { |
|
Load(); |
|
} |
|
else if (stricmp(subject, "Config") == 0) { |
|
Config((HWND)data1); |
|
} |
|
else if (stricmp(subject, "Exit") == 0) { |
|
Exit(); |
|
} |
|
else return 0; |
|
|
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
extern "C" |
|
{ |
|
KMELEON_PLUGIN kmeleonPlugin *GetKmeleonPlugin() |
|
{ |
|
return &kPlugin; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
static TCHAR *GetExpectionCodeText(DWORD dwExceptionCode) { |
|
switch(dwExceptionCode) { |
|
case EXCEPTION_ACCESS_VIOLATION: return _T("ACCESS VIOLATION"); |
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return _T("ARRAY BOUNDS EXCEEDED"); |
|
case EXCEPTION_BREAKPOINT: return _T("BREAKPOINT"); |
|
case EXCEPTION_DATATYPE_MISALIGNMENT: return _T("DATATYPE MISALIGNMENT"); |
|
case EXCEPTION_FLT_DENORMAL_OPERAND: return _T("FLT DENORMAL OPERAND"); |
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return _T("FLT DIVIDE BY ZERO"); |
|
case EXCEPTION_FLT_INEXACT_RESULT: return _T("FLT INEXACT RESULT"); |
|
case EXCEPTION_FLT_INVALID_OPERATION: return _T("FLT INVALID OPERATION"); |
|
case EXCEPTION_FLT_OVERFLOW: return _T("FLT OVERFLOW"); |
|
case EXCEPTION_FLT_STACK_CHECK: return _T("FLT STACK CHECK"); |
|
case EXCEPTION_FLT_UNDERFLOW: return _T("FLT UNDERFLOW"); |
|
case EXCEPTION_ILLEGAL_INSTRUCTION: return _T("ILLEGAL INSTRUCTION"); |
|
case EXCEPTION_IN_PAGE_ERROR: return _T("IN PAGE ERROR"); |
|
case EXCEPTION_INT_DIVIDE_BY_ZERO: return _T("INT DIVIDE BY ZERO"); |
|
case EXCEPTION_INT_OVERFLOW: return _T("INT OVERFLOW"); |
|
case EXCEPTION_INVALID_DISPOSITION: return _T("INVALID DISPOSITION"); |
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return _T("NONCONTINUABLE EXCEPTION"); |
|
case EXCEPTION_PRIV_INSTRUCTION: return _T("PRIV INSTRUCTION"); |
|
case EXCEPTION_SINGLE_STEP: return _T("SINGLE STEP"); |
|
case EXCEPTION_STACK_OVERFLOW: return _T("STACK OVERFLOW"); |
|
case DBG_CONTROL_C : return _T("DBG CONTROL C"); |
|
default: |
|
return _T("<unkown exception>"); |
|
} |
|
} |
|
|
|
|
|
BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr) |
|
{ |
|
MODULEENTRY32 M = {sizeof(M)}; |
|
HANDLE hSnapshot; |
|
|
|
Module_Name[0] = 0; |
|
|
|
if (CreateToolhelp32Snapshot_) { |
|
hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0); |
|
|
|
if ((hSnapshot != INVALID_HANDLE_VALUE) && Module32First_(hSnapshot, &M)) { |
|
do |
|
{ |
|
if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize) { |
|
lstrcpyn(Module_Name, M.szExePath, MAX_PATH); |
|
Module_Addr = M.modBaseAddr; |
|
break; |
|
} |
|
} while (Module32Next_(hSnapshot, &M)); |
|
} |
|
|
|
CloseHandle(hSnapshot); |
|
} |
|
|
|
return !!Module_Name[0]; |
|
} |
|
|
|
|
|
int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str) |
|
{ |
|
PBYTE Module_Addr = 0; |
|
PBYTE Module_Addr_1; |
|
int Str_Len; |
|
|
|
typedef struct STACK |
|
{ |
|
STACK *Ebp; |
|
PBYTE Ret_Addr; |
|
DWORD *Param; |
|
} STACK, * PSTACK; |
|
|
|
STACK Stack = {0, 0}; |
|
PSTACK Ebp; |
|
|
|
if (pException) |
|
{ |
|
Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; |
|
Stack.Ret_Addr = |
|
(PBYTE)pException->ExceptionRecord->ExceptionAddress; |
|
Ebp = &Stack; |
|
} |
|
else |
|
{ |
|
Ebp = (PSTACK)&pException - 1; //frame addr of Get_Call_Stack() |
|
|
|
// Skip frame of Get_Call_Stack(). |
|
if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) |
|
Ebp = Ebp->Ebp; //caller ebp |
|
} |
|
|
|
Str[0] = 0; |
|
Str_Len = 0; |
|
|
|
// Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. |
|
// Break trace on wrong stack frame. |
|
for (int Ret_Addr_I = 0; |
|
(Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && |
|
!IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); |
|
Ret_Addr_I++, Ebp = Ebp->Ebp) |
|
{ |
|
// If module with Ebp->Ret_Addr found. |
|
if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, TmpStr, Module_Addr_1)) { |
|
if (Module_Addr_1 != Module_Addr) { |
|
// Save module's address and full path. |
|
Module_Addr = Module_Addr_1; |
|
Str_Len += wsprintf(Str + Str_Len, NL " %08X %s", |
|
Module_Addr, TmpStr); |
|
} |
|
|
|
// Save call offset. |
|
Str_Len += wsprintf(Str + Str_Len, NL " +%08X", Ebp->Ret_Addr - Module_Addr); |
|
|
|
// Save 5 params of the call. We don't know the real number of params. |
|
if (pException && !Ret_Addr_I) //fake frame for exception address |
|
Str_Len += wsprintf(Str + Str_Len, " <- FAULT"); |
|
else if (!IsBadReadPtr(Ebp, sizeof(PSTACK)) && |
|
!IsBadReadPtr(Ebp->Param, 5 * sizeof(DWORD))) { |
|
Str_Len += wsprintf(Str + Str_Len, " %08X %08X %08X %08X %08X", |
|
Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], |
|
Ebp->Param[3], Ebp->Param[4]); |
|
} |
|
} |
|
else |
|
Str_Len += wsprintf(Str + Str_Len, NL "%08X", Ebp->Ret_Addr); |
|
} |
|
|
|
return Str_Len; |
|
} |
|
|
|
|
|
int WINAPI Get_System_Str(PCHAR Str) |
|
{ |
|
int Str_Len = 0; |
|
SYSTEM_INFO siSysInfo; |
|
GetSystemInfo(&siSysInfo); |
|
|
|
if (siSysInfo.wProcessorArchitecture != |
|
PROCESSOR_ARCHITECTURE_UNKNOWN) { |
|
Str_Len += wsprintf(Str + Str_Len, "Number of processors: %u" NL, |
|
siSysInfo.dwNumberOfProcessors); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, "Processor Type: %s", |
|
siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ? "x86" : |
|
siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ? "IA64" : |
|
siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? "AMD64" : |
|
"<unknown>"); |
|
|
|
if (siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { |
|
Str_Len += wsprintf(Str + Str_Len, " Family %u", |
|
siSysInfo.wProcessorLevel); |
|
Str_Len += wsprintf(Str + Str_Len, " Model %u", |
|
siSysInfo.wProcessorRevision / 256); |
|
Str_Len += wsprintf(Str + Str_Len, " Stepping %u" NL, |
|
siSysInfo.wProcessorRevision % 256); |
|
} |
|
else { |
|
if (siSysInfo.wProcessorLevel) |
|
Str_Len += wsprintf(Str + Str_Len, " Level %u", |
|
siSysInfo.wProcessorLevel); |
|
if (siSysInfo.wProcessorRevision) |
|
Str_Len += wsprintf(Str + Str_Len, " Revision %u" NL, |
|
siSysInfo.wProcessorRevision); |
|
} |
|
} |
|
|
|
return Str_Len; |
|
} |
|
|
|
|
|
int WINAPI Get_Version_Str(PCHAR Str) |
|
{ |
|
int Str_Len = 0; |
|
OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; |
|
|
|
if (!GetVersionEx((POSVERSIONINFO)&V)) { |
|
ZeroMemory(&V, sizeof(V)); |
|
V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
|
GetVersionEx((POSVERSIONINFO)&V); |
|
} |
|
|
|
if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) |
|
V.dwBuildNumber = LOWORD(V.dwBuildNumber); |
|
|
|
if (V.dwMajorVersion == 5) { |
|
if (V.dwMinorVersion == 0) |
|
Str_Len += wsprintf(Str, "Windows 2000 Version: "); |
|
else if (V.dwMinorVersion == 1) |
|
Str_Len += wsprintf(Str, "Windows XP %sVersion: ", |
|
V.wSuiteMask & VER_SUITE_PERSONAL ? "(Home Edition) " : |
|
""); |
|
else if (V.dwMinorVersion == 2) |
|
Str_Len += wsprintf(Str, "Windows Server 2003 Version: "); |
|
} |
|
else if (V.dwMajorVersion == 4) { |
|
if (V.dwMinorVersion == 0) { |
|
if (V.dwPlatformId == VER_PLATFORM_WIN32_NT) |
|
Str_Len += wsprintf(Str, "Windows NT-4 Version: "); |
|
else |
|
Str_Len += wsprintf(Str, "Windows 95 Version: "); |
|
} |
|
else if (V.dwMinorVersion == 10) |
|
Str_Len += wsprintf(Str, "Windows 98 Version: "); |
|
else if (V.dwMinorVersion == 90) |
|
Str_Len += wsprintf(Str, "Windows ME Version: "); |
|
} |
|
|
|
if (!*Str) { |
|
Str_Len += wsprintf(Str, "Windows: %d.%d.%d, SP %d.%d" NL, |
|
V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, |
|
V.wServicePackMajor, V.wServicePackMinor); |
|
} |
|
else { |
|
Str_Len += wsprintf(Str + Str_Len, "%d.%d", V.dwMajorVersion, |
|
V.dwMinorVersion); |
|
if (V.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { |
|
Str_Len += wsprintf(Str + Str_Len, " %s", V.szCSDVersion); |
|
} |
|
Str_Len += wsprintf(Str + Str_Len, NL); |
|
|
|
if (V.dwBuildNumber) { |
|
Str_Len += wsprintf(Str + Str_Len, "Current Build: %d" NL, |
|
V.dwBuildNumber); |
|
} |
|
|
|
if (V.wServicePackMajor) { |
|
Str_Len += wsprintf(Str + Str_Len, "Service Pack: %d", |
|
V.wServicePackMajor); |
|
if (V.wServicePackMinor) |
|
Str_Len += wsprintf(Str + Str_Len, ".%d,", |
|
V.wServicePackMinor); |
|
Str_Len += wsprintf(Str + Str_Len, NL); |
|
} |
|
|
|
if (V.wProductType) { |
|
Str_Len += wsprintf(Str + Str_Len, "Current Type: %s" NL, |
|
V.wProductType == VER_NT_WORKSTATION ? "Workstation" : |
|
V.wProductType == VER_NT_DOMAIN_CONTROLLER ? "Domain Controller" : |
|
V.wProductType == VER_NT_SERVER ? "Server" : |
|
"<unknown>"); |
|
} |
|
} |
|
|
|
return Str_Len; |
|
} |
|
|
|
|
|
PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) |
|
{ |
|
int Str_Len; |
|
PBYTE Module_Addr; |
|
HANDLE hFile; |
|
FILETIME Last_Write_Time; |
|
FILETIME Local_File_Time; |
|
DWORD dwFileSize; |
|
DWORD dwRet; |
|
SYSTEMTIME T; |
|
TIME_ZONE_INFORMATION TZI; |
|
|
|
if (!Str) |
|
return NULL; |
|
|
|
Str_Len = 0; |
|
|
|
Str_Len += wsprintf(Str + Str_Len, NL "K-Meleon Crash Information" NL NL); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, "Application exception occurred:" NL); |
|
|
|
GetLocalTime(&T); |
|
Str_Len += wsprintf(Str + Str_Len, " Date: %02d-%02d-%02d @ %02d:%02d", |
|
T.wYear, T.wMonth, T.wDay, T.wHour, T.wMinute); |
|
|
|
dwRet = GetTimeZoneInformation(&TZI); |
|
if (TZI.Bias && !(TZI.Bias % 60)) { |
|
Str_Len += wsprintf(Str + Str_Len, " %s%d", |
|
TZI.Bias < 0 ? "+" : "-", abs(TZI.Bias) / 60); |
|
} |
|
|
|
WideCharToMultiByte(CP_OEMCP, 0, |
|
dwRet == TIME_ZONE_ID_STANDARD ? TZI.StandardName : |
|
dwRet == TIME_ZONE_ID_DAYLIGHT ? TZI.DaylightName : |
|
L"", -1, TmpStr, MAX_PATH, NULL, NULL); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, ", %s" NL, TmpStr); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, " Exception: %08X (", |
|
pException->ExceptionRecord->ExceptionCode); |
|
Str_Len += wsprintf(Str + Str_Len, |
|
GetExpectionCodeText(pException->ExceptionRecord->ExceptionCode)); |
|
if (pException->ExceptionRecord->ExceptionCode == |
|
EXCEPTION_ACCESS_VIOLATION) { |
|
Str_Len += wsprintf(Str + Str_Len, ", %s Address: %08X", |
|
(pException->ExceptionRecord->ExceptionInformation[0]) ? |
|
"Writing" : "Reading", |
|
pException->ExceptionRecord->ExceptionInformation[1]); |
|
} |
|
Str_Len += wsprintf(Str + Str_Len, ")" NL); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, " Process: "); |
|
GetModuleFileName(NULL, TmpStr, MAX_PATH); |
|
Str_Len += wsprintf(Str + Str_Len, "%s" NL, TmpStr); |
|
|
|
if (Get_Module_By_Ret_Addr((PBYTE)pException->ExceptionRecord->ExceptionAddress, |
|
TmpStr, Module_Addr)) { |
|
Str_Len += wsprintf(Str + Str_Len, " Module: %s" NL, TmpStr); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, " File Date and Size: "); |
|
if ((hFile = CreateFile(TmpStr, GENERIC_READ, |
|
FILE_SHARE_READ, NULL, OPEN_EXISTING, |
|
FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { |
|
if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) { |
|
FileTimeToLocalFileTime(&Last_Write_Time, |
|
&Local_File_Time); |
|
FileTimeToSystemTime(&Local_File_Time, &T); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, "%02d-%02d-%02d @ %02d:%02d, ", |
|
T.wYear, T.wMonth, T.wDay, T.wHour, T.wMinute); |
|
} |
|
|
|
dwFileSize = GetFileSize(hFile, NULL); |
|
if (dwFileSize != INVALID_FILE_SIZE) |
|
Str_Len += wsprintf(Str + Str_Len, "%u bytes", |
|
dwFileSize); |
|
CloseHandle(hFile); |
|
} |
|
Str_Len += wsprintf(Str + Str_Len, NL); |
|
} |
|
else { |
|
Str_Len += wsprintf(Str + Str_Len, " Exception Addr: %08X" NL, |
|
pException->ExceptionRecord->ExceptionAddress); |
|
} |
|
|
|
Str_Len += wsprintf(Str + Str_Len, NL "*----> System Information <----*" NL); |
|
Str_Len += Get_System_Str(Str + Str_Len); |
|
Str_Len += Get_Version_Str(Str + Str_Len); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, NL "*----> Stack Back Trace <----*"); |
|
Str_Len += wsprintf(Str + Str_Len, NL "ReturnAddr Param#1 Param#2 Param#3 Param#4 Param#5"); |
|
Str_Len += Get_Call_Stack(pException, Str + Str_Len); |
|
|
|
Str_Len += wsprintf(Str + Str_Len, NL); |
|
|
|
return Str; |
|
} |
|
|
|
|
|
static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pException) |
|
{ |
|
if (pException->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { |
|
return EXCEPTION_CONTINUE_SEARCH; |
|
} |
|
|
|
if (Str && !*Str) |
|
Str = Get_Exception_Info(pException); |
|
|
|
if (Str && *Str) { |
|
HANDLE hDump_File; |
|
DWORD Bytes; |
|
|
|
lstrcat(Str, NL NL); |
|
|
|
hDump_File = CreateFile(Dump_Path, |
|
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
|
|
|
if (hDump_File) { |
|
WriteFile(hDump_File, Str, lstrlen(Str), &Bytes, NULL); |
|
CloseHandle(hDump_File); |
|
} |
|
} |
|
|
|
if (Str) { |
|
CHAR *cptr = NULL; |
|
GetModuleFileName(NULL, TmpStr, MAX_PATH); |
|
if (*TmpStr) |
|
cptr = strrchr(TmpStr, '\\'); |
|
|
|
wsprintf(Str, |
|
"The application %s%shas generated an error and will be closed by Windows." NL NL |
|
"An error log has been written:" NL |
|
" %s" NL NL |
|
"You will need to restart the program. If the problem persists, contact the" NL |
|
"program vendor. Describe the problem in detail and attach the latest error log." NL NL, |
|
cptr ? cptr+1 : *TmpStr ? TmpStr : "", |
|
cptr ? " " : *TmpStr ? " " : "", Dump_Path); |
|
MessageBox(NULL, Str, "Application Error", MB_ICONWARNING | MB_OK); |
|
|
|
// FatalAppExit(0, Str); |
|
return EXCEPTION_EXECUTE_HANDLER; |
|
} |
|
|
|
return EXCEPTION_CONTINUE_SEARCH; |
|
}
|
|
|