Adapted to cursor/icon handling changes.
[wine/multimedia.git] / win32 / except.c
blobd65cf6ec42bcc1e69d33b5db5cd37ccf729db1db
1 /*
2 * Win32 exception functions
4 * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
6 * Notes:
7 * What really happens behind the scenes of those new
8 * __try{...}__except(..){....} and
9 * __try{...}__finally{...}
10 * statements is simply not documented by Microsoft. There could be different
11 * reasons for this:
12 * One reason could be that they try to hide the fact that exception
13 * handling in Win32 looks almost the same as in OS/2 2.x.
14 * Another reason could be that Microsoft does not want others to write
15 * binary compatible implementations of the Win32 API (like us).
17 * Whatever the reason, THIS SUCKS!! Ensuring portabilty or future
18 * compatability may be valid reasons to keep some things undocumented.
19 * But exception handling is so basic to Win32 that it should be
20 * documented!
22 * Fixmes:
23 * -Most functions need better parameter checking.
24 * -I do not know how to handle exceptions within an exception handler.
25 * or what is done when ExceptionNestedException is returned from an
26 * exception handler
27 * -Real exceptions are not yet implemented. only the exception functions
28 * are implemented. A real implementation needs some new code in
29 * loader/signal.c. There would also be a need for showing debugging
30 * information in UnhandledExceptionFilter.
34 #include <assert.h>
35 #include "winuser.h"
36 #include "winerror.h"
37 #include "ldt.h"
38 #include "process.h"
39 #include "thread.h"
40 #include "debug.h"
41 #include "except.h"
42 #include "stackframe.h"
44 #define TEB_EXCEPTION_FRAME(pcontext) \
45 ((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
47 /*******************************************************************
48 * RtlUnwind (KERNEL32.443)
50 * This function is undocumented. This is the general idea of
51 * RtlUnwind, though. Note that error handling is not yet implemented.
53 * The real prototype is:
54 * void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
55 * PEXCEPTION_RECORD pRecord, DWORD returnEax );
57 REGS_ENTRYPOINT(RtlUnwind)
59 EXCEPTION_RECORD record;
60 DWORD dispatch;
61 int retval;
62 PEXCEPTION_FRAME pEndFrame;
63 PEXCEPTION_RECORD pRecord;
65 /* get the arguments from the stack */
67 DWORD ret = STACK32_POP(context); /* return addr */
68 pEndFrame = (PEXCEPTION_FRAME)STACK32_POP(context);
69 (void)STACK32_POP(context); /* unused arg */
70 pRecord = (PEXCEPTION_RECORD)STACK32_POP(context);
71 EAX_reg(context) = STACK32_POP(context);
72 STACK32_PUSH(context,ret); /* restore return addr */
74 /* build an exception record, if we do not have one */
75 if(!pRecord)
77 record.ExceptionCode = STATUS_INVALID_DISPOSITION;
78 record.ExceptionFlags = 0;
79 record.ExceptionRecord = NULL;
80 record.ExceptionAddress = (LPVOID)EIP_reg(context);
81 record.NumberParameters = 0;
82 pRecord = &record;
85 if(pEndFrame)
86 pRecord->ExceptionFlags|=EH_UNWINDING;
87 else
88 pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
90 /* get chain of exception frames */
91 while ((TEB_EXCEPTION_FRAME(context) != NULL) &&
92 (TEB_EXCEPTION_FRAME(context) != ((void *)0xffffffff)) &&
93 (TEB_EXCEPTION_FRAME(context) != pEndFrame))
95 TRACE(win32, "calling exception handler at 0x%x\n",
96 (int)TEB_EXCEPTION_FRAME(context)->Handler );
98 dispatch=0;
99 retval = TEB_EXCEPTION_FRAME(context)->Handler( pRecord,
100 TEB_EXCEPTION_FRAME(context),
101 context, &dispatch);
103 TRACE(win32,"exception handler returns 0x%x, dispatch=0x%x\n",
104 retval, (int) dispatch);
106 if ( (retval == ExceptionCollidedUnwind) &&
107 (TEB_EXCEPTION_FRAME(context) != (LPVOID)dispatch)
109 TEB_EXCEPTION_FRAME(context) = (LPVOID)dispatch;
110 else if ( (TEB_EXCEPTION_FRAME(context) != pEndFrame) &&
111 (TEB_EXCEPTION_FRAME(context) != TEB_EXCEPTION_FRAME(context)->Prev)
113 TEB_EXCEPTION_FRAME(context) = TEB_EXCEPTION_FRAME(context)->Prev;
114 else
115 break;
120 /*******************************************************************
121 * RaiseException (KERNEL32.418)
123 * The real prototype is:
124 * void WINAPI EXC_RaiseException(DWORD dwExceptionCode,
125 * DWORD dwExceptionFlags,
126 * DWORD cArguments,
127 * const LPDWORD lpArguments );
129 REGS_ENTRYPOINT(RaiseException)
131 PEXCEPTION_FRAME pframe;
132 EXCEPTION_RECORD record;
133 DWORD dispatch; /* is this used in raising exceptions ?? */
134 int retval;
135 int i;
137 /* Get the arguments from the stack */
139 DWORD ret = STACK32_POP(context); /* return addr */
140 DWORD dwExceptionCode = STACK32_POP(context);
141 DWORD dwExceptionFlags = STACK32_POP(context);
142 DWORD cArguments = STACK32_POP(context);
143 const LPDWORD lpArguments = (LPDWORD)STACK32_POP(context);
144 STACK32_PUSH(context,ret); /* Restore the return address */
146 /* compose an exception record */
148 record.ExceptionCode = dwExceptionCode;
149 record.ExceptionFlags = dwExceptionFlags;
150 record.ExceptionRecord = NULL;
151 record.NumberParameters = cArguments;
152 record.ExceptionAddress = (LPVOID)EIP_reg(context);
154 if (lpArguments) for( i = 0; i < cArguments; i++)
155 record.ExceptionInformation[i] = lpArguments[i];
157 /* get chain of exception frames */
159 retval = ExceptionContinueSearch;
160 pframe = TEB_EXCEPTION_FRAME( context );
162 while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
164 PEXCEPTION_FRAME prevframe;
165 TRACE(win32,"calling exception handler at 0x%x\n",
166 (int) pframe->Handler);
167 dispatch=0;
168 TRACE(relay,"(except=%p,record=%p,frame=%p,context=%p,dispatch=%p)\n",
169 pframe->Handler, &record, pframe, context, &dispatch );
170 prevframe = pframe->Prev;
171 retval=pframe->Handler(&record,pframe,context,&dispatch);
173 TRACE(win32,"exception handler returns 0x%x, dispatch=0x%x\n",
174 retval, (int) dispatch);
176 if(retval==ExceptionContinueExecution)
177 break;
178 pframe=prevframe;
181 if (retval!=ExceptionContinueExecution)
183 /* FIXME: what should we do here? */
184 TRACE(win32,"no handler wanted to handle the exception, exiting\n");
185 ExitProcess(dwExceptionCode); /* what status should be used here ? */
190 /*******************************************************************
191 * UnhandledExceptionFilter (KERNEL32.537)
193 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
195 char message[80];
196 PDB *pdb = PROCESS_Current();
198 /* FIXME: Should check if the process is being debugged */
200 if (pdb->top_filter)
202 DWORD ret = pdb->top_filter( epointers );
203 if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
206 /* FIXME: Should check the current error mode */
208 sprintf( message, "Unhandled exception 0x%08lx at address 0x%08lx.",
209 epointers->ExceptionRecord->ExceptionCode,
210 (DWORD)epointers->ExceptionRecord->ExceptionAddress );
211 MessageBoxA( 0, message, "Error", MB_OK | MB_ICONHAND );
212 return EXCEPTION_EXECUTE_HANDLER;
216 /*************************************************************
217 * SetUnhandledExceptionFilter (KERNEL32.516)
219 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
220 LPTOP_LEVEL_EXCEPTION_FILTER filter )
222 PDB *pdb = PROCESS_Current();
223 LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
224 pdb->top_filter = filter;
225 return old;