April 27, 2024, 01:43:32 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Unhandled exception handler

Started by sapero, October 16, 2009, 05:16:00 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

sapero

October 16, 2009, 05:16:00 AM Last Edit: October 18, 2009, 09:59:20 AM by sapero
This is a dll project which in case of an exception opens a dialog with usefull informations - exception type, address, and recently called subroutines.
You do not need to compile in debug mode to make it working, just keep the .map and .o files (in Ebasic you must enable map file generation in project/compile options).
Requires DbgHelp.dll 6.0 or later http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
DbgHelp.dll is loaded dynamically, so if it fails to load, you will see a blank callstack.

The code uses SetUnhandledExceptionFilter api to install the final exception handler for current process. When you get a crash, a customized window will open, and optionally your callback function will be called. Then a thread is created, where the .map file is parsed for all public symbols, and later all .o files are scanned for nonpublic function names. All the names are added to debughelp library via SymAddSymbol api.

There is a user defined button: you can enable it, change its text and respond to click event. It was designed to have last-chance to save any unsaved work. For example - if you have multiple document interface with scintilla controls, you still can grab modified text and save all documents. But please do not use message based functions (like SendMessage) to communicate with your windows, because the window-creator thread is suspeded. If you have scintilla controls, use direct calls instead SendMessage. If your using CScintilla class, this is already implemented.

I have included two small examples for Aurora and Emergence.

This is my implementation from a MDI application:
sub main()
{
InitializeUnhandledExceptionFilter(&ChildEmergencyHasOpenedWindows, &ChildEmergencySaveMyWork);
...
}

sub ChildEmergencyHasOpenedWindows(HWND hwndButton),BOOL
{
return RtlFirstEntrySList(&g_childlist); // enable button if any MDI child is opened
}

sub ChildEmergencySaveMyWork(HWND hwndParent)
{
CHILD_ENTRY *first = RtlFirstEntrySList(&g_childlist);
CHILD_ENTRY *node = first;

int modifiedCount = 0;
int savedCount = 0;

while (node)
{
CHILDDATA *data = node->data;

if (data->sci->GetModify()) // data->sci points to CScintilla class
{
modifiedCount++;
// save document: sci->GetTextLength, new, sci->SciGetText, WriteFile...
if (ChildSaveAs(data, hwndParent)) savedCount++;
}
node = node->Next;
if (node == first) break;
}
TCHAR szInfo[80];
_sntprintf(&szInfo, 80, TEXT("Successfully saved %d from total %d modified documents"), savedCount, modifiedCount);
MessageBox(hwndParent, szInfo, TEXT("Emergency"), MB_ICONINFORMATION);
}


Please note: manual symbol loading is pretty slow (at least with dbghelp <=6.11). The exceptionLoadSymbols subroutine executes very fast, but the call to SymAddSymbol is very slow. Walking the callstack in turn is very slow with dbgHelp.dll from Aurora/bin directory, so I have downloaded the newest version, installed in default location, and added its path as the first path for LoadLibrary.

EDIT - removed copy-bug.