Hey guys, have a question a little off topic for ASM and more towards C++/MFC. (I think)

When an application crashes abnormally. Something you don't assert, just a plain run of the mill "crash". Is there a way to perform some final actions before the application terminates.

The application I am working on for work has the odd crash. I want to safeguard the data by performing a save of the data to a temp recovery file before it dies so that the work of the end user is not lost. Then the app can reload this recovery file with their work.

How would you do this? If possible, any MFC/C++ programmers can indicate the MFC/C++ way of doing this that would be great.

thanx
Posted on 2002-01-29 18:24:21 by Rockinronstar
You can use below proc for detection



.data?
exceptbuff db 207 dup(?)
.code
invoke SetUnhandledExceptionFilter,offset MydumyProc

int 3 ;lets make and exception



MydumyProc PROC uses ebx esi edi exp:DWORD
mov eax, (EXCEPTION_POINTERS ptr [exp]).pExceptionRecord
mov ebx, (EXCEPTION_POINTERS ptr[eax]).ContextRecord
mov eax, (EXCEPTION_RECORD ptr[eax]).ExceptionCode
push (EXCEPTION_RECORD ptr[eax]).ExceptionAddress
push (EXCEPTION_RECORD ptr[eax]).ExceptionCode
push CTEXT('Program caused %.8lXh exception at %.8lXh!',0dh,0ah)
push offset exceptbuff
call wsprintf
add esp, 10h
add eax,offset exceptbuff
assume ebx:PTR CONTEXT

push [ebx].regEax
push [ebx].regEbx
push [ebx].regEcx
push [ebx].regEdx
push [ebx].regEsi
push [ebx].regEdi
push [ebx].regEsp
push [ebx].regEbp
push [ebx].regEip
push offset regcont
push eax
call wsprintf
add esp, 2Ch

invoke MessageBox,0,addr exceptbuff,0,MB_OK
invoke MessageBox,0,CTEXT('Do you want to continue ?'),0,MB_YESNO
xor eax,IDYES
jz @exit
ret
@exit:
;We can only pass int3 exception other exceptions
will keep asking you to contiue or not.

dec eax
ret
MydumyProc ENDP


It will show you the exception EIP registers.You can do whatever you want at this point.Hope it helps.
Posted on 2002-01-29 19:35:54 by LaptoniC
If you want more fine-grained control, look up Structured Exception Handling
aka SEH. Quite nice stuff really :). But if SetUnhandledExceptionFilter
does it for you, stay with that - it's a bit simpler.
Posted on 2002-01-29 20:20:30 by f0dder
that worked great.

What I did was use my own Function to handle the exception and then set the old global exception handling back to default and let it spit up the messagebox and close the app

sound like the proper way to do it?

I also noticed you can even prevent Windows from closing the app and try and keep working. I ran into a problem with that right away!! tried resuming after a write to "bad RAM" and the whole computer almost blew up, haha

seems best to do what you need, in my case save all data to a recovery file and then let Windows do its stuff and close the app like it wants to
Posted on 2002-01-29 22:07:43 by Rockinronstar
seems best to do what you need, in my case save all data to a recovery file and then let Windows do its stuff and close the app like it wants to


Phew, I wish the big software developers (like Adobe, Corel, Microsoft, Lotus,..) would care about crashes like you do.

Just my opinion.
YaWNS aka Stefan K
Posted on 2002-01-30 07:05:03 by YaWNS
me too, haha. The only big app I know of that saves a recovery file on crash is 3D Studio Max. I don't think they don't care, i think they don't know how to do it.

I have safeguarded my entire app and have already gained some applause at work for it. It makes people feel more at ease knowing the safeguard exists
Posted on 2002-01-30 11:07:40 by Rockinronstar
Nice code laptonic!
Posted on 2002-01-30 11:37:07 by Will
Rockinstar wrote: ...I don't think they don't care, i think they don't know how to do it.


II've never came across a developer who wants their source to crash and keep returning for defect management. I have, however, met management who doesn't want to allow the developers to plan and code properly versus get it out the door now, not tomarrow... and then treat each defect as a source of revenue for the next update/release...

I, personally, when I wrote software for the police depts., took the time to design the product and then write extensive error handling and such, and let them do the testing pretty much... in three years, I've never had a single bug complaint on 4 different products... and it only took me about 2 weeks or so the get the design finalized... so, large corporations can do it too... just a matter of whether management sees the value in waiting for a spec when they would rather see "tangeable progress" and if they can't see it or interact with it, it's not being progressed in their point-of-view. It's a shame. Beacuse we get blamed, not the managers... they think they're correct by doing this...

the by product of this is that software is not stable. I make it a habbit to design it whether they like it or not. I'm always late on deadlines but they can't argue with customer satisfaction (when I'm employed doing it)... because nothing I work on returns for defects... no complaints is good news... (or bad, if you're hoping for revenue on defect correction)... as a result, they changed theyr pricing strategy to include subscriptions for updates/upgrades if any... rather than a per-update payment.



Thanks,
_Shawn
Posted on 2002-01-30 12:30:16 by _Shawn
_Shawn, that is what I strive for as well

Still nice to have a safeguard saving system in case the inevitable happens. But always best to never have to use it.
Posted on 2002-01-30 14:57:47 by Rockinronstar
try to play around with REAL seh like f0dder pointed out...



ASSUME FS:NOTHING

PUSHAD
LEA EAX, EXCEPTIONHANDLER
PUSH EAX
PUSH FS:[0]
MOV FS:[0], ESP

;PASTE YOUR CODE THAT COULD CAUSE
;AN ERROR... IF EVERYTHING WORKED
;FINE YOU HAVE TO RESTORE YOUR SEH!

JMP RESTORESEH

EXCEPTIONHANDLER:

MOV ESP, [ESP+8]

;SOME ERROR OCCURED, DO WHAT YOU
;WANT TO DO NOW... BUT DON'T
;FORGET TO RESTORE YOUR SEH...

RESTORESEH:

POP FS:[0]
ADD ESP, 4
POPAD


that's a very basic SEH frame, i wouldn't mess with the
stack or you could produce a gpf *after* the frame :)
Posted on 2002-01-31 06:26:42 by mob
I have done quite a bit of research and code writing with them already. I have fully safeguarded any possibility of errors destroying the end users data. Haven't had a crash on it yet but the thing about crashes is, you never know when they will happen.

You can write as much error trapping as you want but if the problem is with other programs causing instability in the OS then your up the creek. This seems like the best way to safeguard data. Ever crash for any reason save the users data to a recovery file.

It works quite well. I simulated a crash with int 3 and popped up a message indicating there was a crash and before I terminated the app I saved the data at its current state to a temp recovery file and then updated the .ini file indicating there was a crash recovery file made so next time they open the app I pop up an option to restore pre-crash project data


looks very professional, and if it ever needs to be called , I am sure someone will be thankful it exists
Posted on 2002-01-31 06:58:24 by Rockinronstar
if the problem is not caused by your prog you can't do
ANYTHING to avoid what will happen to your app... but
you can secure YOUR programm with seh-handlers and
somthing likea autosave feature... if you really need
this security add one or more seh handlers to your code
and save whatever needs to be saved every... say 10
minutes in a backup-file... you can also use flags to
indicate that your app was forced to close due to a
system-exception... (flag on prog-start, flag on prog
-end; if end-flag is missing something stange happened)
a couple of texteditors use similar features... i don't
use seh very often... i mean why? if you write clean
code there is no reason... autosave is far more
important then seh i think...
Posted on 2002-01-31 07:14:11 by mob
the instabilities some apps cause when they go bad can easily disrupt your own application. Take this case: it starts gobbling up memory very quickly, or even DC's very quickly. Then your app requests some RAM or a DC and there isn't any available. I am sure that every function in a persons app has exception handlers around themselves. In order for this to be effective you would need an try..catch system around every function. But this is rare, the system will probably never get to this point, maybe on Win95/98. I have had apps that have gone nuts and done the exact thing I mentioned which crashed everything open.

I like the idea of a last resort handler in case the worst happens.

And it eliminates the overhead of having exception handling in numerous places in your code.
Posted on 2002-01-31 12:07:01 by Rockinronstar
I am trying to make your SetUnhandledExceptionFilter...I get ( syntax error : ,) I comment out CTEXT because I don't think i set it up right.... Could you tell me what i am doing wrong...

.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:SWORD

include \MASM32\INCLUDE\windows.inc
include \MASM32\INCLUDE\user32.inc
include \MASM32\INCLUDE\kernel32.inc

includelib \MASM32\LIB\user32.lib
includelib \MASM32\LIB\kernel32.lib

MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
MydumyProc PROTO :DWORD

wsprintfA PROTO C :DWORD,:VARARG
wsprintf equ <wsprintfA>

.data

MyText db "Message Box Only",0

exceptbuff db 207 dup(?)
regcont dd ?
CTEXT dd ?

.data?

.code
Main:
; ..................................................................................................

invoke SetUnhandledExceptionFilter,offset MydumyProc

;;;;;;;;;;;;;;int 3 ;lets make and exception

invoke MessageBoxA, NULL, ADDR MyText, NULL, NULL
invoke ExitProcess,0
; ..................................................................................................

MydumyProc PROC uses ebx esi edi exp:DWORD
mov eax, (EXCEPTION_POINTERS ptr ).pExceptionRecord
mov ebx, (EXCEPTION_POINTERS ptr).ContextRecord
mov eax, (EXCEPTION_RECORD ptr).ExceptionCode
push (EXCEPTION_RECORD ptr).ExceptionAddress
push (EXCEPTION_RECORD ptr).ExceptionCode
;;;;;;;;;;;;;;push CTEXT, ('Program caused %.8lXh exception at %.8lXh!',0dh,0ah)
push offset exceptbuff
call wsprintf
add esp, 10h
add eax,offset exceptbuff
assume ebx:PTR CONTEXT

push .regEax
push .regEbx
push .regEcx
push .regEdx
push .regEsi
push .regEdi
push .regEsp
push .regEbp
push .regEip
push offset regcont
push eax
call wsprintf
add esp, 2Ch

invoke MessageBox,0,addr exceptbuff,0,MB_OK
;;;;;;;;;;;;;;invoke MessageBox,0,CTEXT('Do you want to continue ?'),0,MB_YESNO

xor eax,IDYES
jz @exit
ret
@exit:

dec eax
ret
MydumyProc ENDP
end Main
Posted on 2002-01-31 19:59:55 by cmax
Most probably you dont have definitions of structures I use.They are in windows.inc maybe your is outdate.Define this structures



EXCEPTION_MAXIMUM_PARAMETERS equ 15
SIZE_OF_80387_REGISTERS equ 80
MAXIMUM_SUPPORTED_EXTENSION equ 512

FLOATING_SAVE_AREA STRUCT
ControlWord DWORD ?
StatusWord DWORD ?
TagWord DWORD ?
ErrorOffset DWORD ?
ErrorSelector DWORD ?
DataOffset DWORD ?
DataSelector DWORD ?
RegisterArea BYTE SIZE_OF_80387_REGISTERS dup(?)
Cr0NpxState DWORD ?
FLOATING_SAVE_AREA ENDS

CONTEXT STRUCT
ContextFlags DWORD ?
iDr0 DWORD ?
iDr1 DWORD ?
iDr2 DWORD ?
iDr3 DWORD ?
iDr6 DWORD ?
iDr7 DWORD ?
FloatSave FLOATING_SAVE_AREA <>
regGs DWORD ?
regFs DWORD ?
regEs DWORD ?
regDs DWORD ?
regEdi DWORD ?
regEsi DWORD ?
regEbx DWORD ?
regEdx DWORD ?
regEcx DWORD ?
regEax DWORD ?
regEbp DWORD ?
regEip DWORD ?
regCs DWORD ?
regFlag DWORD ?
regEsp DWORD ?
regSs DWORD ?
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS

EXCEPTION_POINTERS STRUCT
pExceptionRecord DWORD ?
ContextRecord DWORD ?
EXCEPTION_POINTERS ENDS

EXCEPTION_RECORD STRUCT
ExceptionCode DWORD ?
ExceptionFlags DWORD ?
pExceptionRecord DWORD ?
ExceptionAddress DWORD ?
NumberParameters DWORD ?
ExceptionInformation DWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?)
EXCEPTION_RECORD ENDS
Posted on 2002-01-31 21:21:34 by LaptoniC