Merged msacm and msacm32 dlls.
[wine] / win32 / except.c
1 /*
2  * Win32 exception functions
3  *
4  * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
5  * Copyright (c) 1999 Alexandre Julliard
6  *
7  * Notes:
8  *  What really happens behind the scenes of those new
9  *  __try{...}__except(..){....}  and
10  *  __try{...}__finally{...}
11  *  statements is simply not documented by Microsoft. There could be different
12  *  reasons for this: 
13  *  One reason could be that they try to hide the fact that exception 
14  *  handling in Win32 looks almost the same as in OS/2 2.x.  
15  *  Another reason could be that Microsoft does not want others to write
16  *  binary compatible implementations of the Win32 API (like us).  
17  *
18  *  Whatever the reason, THIS SUCKS!! Ensuring portabilty or future 
19  *  compatability may be valid reasons to keep some things undocumented. 
20  *  But exception handling is so basic to Win32 that it should be 
21  *  documented!
22  *
23  */
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "ntddk.h"
32 #include "wine/exception.h"
33 #include "ldt.h"
34 #include "callback.h"
35 #include "process.h"
36 #include "thread.h"
37 #include "stackframe.h"
38 #include "server.h"
39 #include "debugtools.h"
40
41 DEFAULT_DEBUG_CHANNEL(seh);
42
43
44 /*******************************************************************
45  *         RaiseException  (KERNEL32.418)
46  */
47 void WINAPI RaiseException( DWORD code, DWORD flags, DWORD nbargs, const LPDWORD args )
48 {
49     EXCEPTION_RECORD record;
50
51     /* Compose an exception record */ 
52     
53     record.ExceptionCode    = code;
54     record.ExceptionFlags   = flags & EH_NONCONTINUABLE;
55     record.ExceptionRecord  = NULL;
56     record.ExceptionAddress = RaiseException;
57     if (nbargs && args)
58     {
59         if (nbargs > EXCEPTION_MAXIMUM_PARAMETERS) nbargs = EXCEPTION_MAXIMUM_PARAMETERS;
60         record.NumberParameters = nbargs;
61         memcpy( record.ExceptionInformation, args, nbargs * sizeof(*args) );
62     }
63     else record.NumberParameters = 0;
64
65     RtlRaiseException( &record );
66 }
67
68
69 /*******************************************************************
70  *         UnhandledExceptionFilter   (KERNEL32.537)
71  */
72 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
73 {
74     struct exception_event_request *req = get_req_buffer();
75     PDB*                pdb = PROCESS_Current();
76     char                format[256];
77     char                buffer[256];
78     HKEY                hDbgConf;
79     DWORD               bAuto = FALSE;
80     DWORD               ret = EXCEPTION_EXECUTE_HANDLER;
81
82     /* send a last chance event to the debugger */
83     req->record  = *epointers->ExceptionRecord;
84     req->first   = 0;
85     req->context = *epointers->ContextRecord;
86     if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = req->context;
87     switch (req->status)
88     {
89     case DBG_CONTINUE: 
90        return EXCEPTION_CONTINUE_EXECUTION;
91     case DBG_EXCEPTION_NOT_HANDLED: 
92        TerminateProcess( GetCurrentProcess(), epointers->ExceptionRecord->ExceptionCode );
93        break; /* not reached */
94     case 0: /* no debugger is present */
95        break;
96     default:    
97        FIXME("Unsupported yet debug continue value %d (please report)\n", req->status);
98     }
99
100     if (pdb->top_filter)
101     {
102         DWORD ret = pdb->top_filter( epointers );
103         if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
104     }
105
106     /* FIXME: Should check the current error mode */
107
108     if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, 
109                      "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 
110                      &hDbgConf)) {
111        DWORD    type;
112        DWORD    count;
113        
114        count = sizeof(format);
115        if (RegQueryValueExA(hDbgConf, "Debugger", 0, &type, format, &count))
116           format[0] = 0;
117
118        count = sizeof(bAuto);
119        if (RegQueryValueExA(hDbgConf, "Auto", 0, &type, (char*)&bAuto, &count))
120           bAuto = FALSE;
121        
122        RegCloseKey(hDbgConf);
123     } else {
124        /* format[0] = 0; */
125        strcpy(format, "debugger/winedbg %ld %ld");
126     }
127
128     if (!bAuto && Callout.MessageBoxA) {
129        sprintf( buffer, "Unhandled exception 0x%08lx at address 0x%08lx.\n"
130                         "Do you wish to debug it ?",
131                 epointers->ExceptionRecord->ExceptionCode,
132                 (DWORD)epointers->ExceptionRecord->ExceptionAddress );
133        if (Callout.MessageBoxA( 0, buffer, "Error", MB_YESNO | MB_ICONHAND ) == IDNO) {
134           TRACE("Killing process\n");
135           return EXCEPTION_EXECUTE_HANDLER;
136        }
137     }
138     
139     if (format[0]) {
140        HANDLE                   hEvent;
141        PROCESS_INFORMATION      info;
142        STARTUPINFOA             startup;
143
144        TRACE("Starting debugger (fmt=%s)\n", format);
145        hEvent = ConvertToGlobalHandle(CreateEventA(NULL, FALSE, FALSE, NULL));
146        sprintf(buffer, format, GetCurrentProcessId(), hEvent);
147        memset(&startup, 0, sizeof(startup));
148        startup.cb = sizeof(startup);
149        startup.dwFlags = STARTF_USESHOWWINDOW;
150        startup.wShowWindow = SW_SHOWNORMAL;
151        if (CreateProcessA(NULL, buffer, NULL, NULL, 
152                           TRUE, 0, NULL, NULL, &startup, &info)) {
153           WaitForSingleObject(hEvent, INFINITE);
154           ret = EXCEPTION_CONTINUE_SEARCH;
155        } else {
156           ERR("Couldn't start debugger (%s) (%ld)\n", buffer, GetLastError());
157        }
158        CloseHandle(hEvent);
159     } else {
160        ERR("No standard debugger defined in the registry => no debugging session\n");
161     }
162     
163     return ret;
164 }
165
166
167 /***********************************************************************
168  *            SetUnhandledExceptionFilter   (KERNEL32.516)
169  */
170 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
171                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
172 {
173     PDB *pdb = PROCESS_Current();
174     LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
175     pdb->top_filter = filter;
176     return old;
177 }
178
179
180 /**************************************************************************
181  *           FatalAppExit16   (KERNEL.137)
182  */
183 void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
184 {
185     WARN("AppExit\n");
186     FatalAppExitA( action, str );
187 }
188
189
190 /**************************************************************************
191  *           FatalAppExitA   (KERNEL32.108)
192  */
193 void WINAPI FatalAppExitA( UINT action, LPCSTR str )
194 {
195     WARN("AppExit\n");
196     Callout.MessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
197     ExitProcess(0);
198 }
199
200
201 /**************************************************************************
202  *           FatalAppExitW   (KERNEL32.109)
203  */
204 void WINAPI FatalAppExitW( UINT action, LPCWSTR str )
205 {
206     WARN("AppExit\n");
207     Callout.MessageBoxW( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
208     ExitProcess(0);
209 }
210
211
212 /*************************************************************
213  *            WINE_exception_handler
214  *
215  * Exception handler for exception blocks declared in Wine code.
216  */
217 DWORD WINE_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
218                               CONTEXT *context, LPVOID pdispatcher )
219 {
220     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
221
222     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
223         return ExceptionContinueSearch;
224     if (wine_frame->u.filter)
225     {
226         EXCEPTION_POINTERS ptrs;
227         ptrs.ExceptionRecord = record;
228         ptrs.ContextRecord = context;
229         switch(wine_frame->u.filter( &ptrs ))
230         {
231         case EXCEPTION_CONTINUE_SEARCH:
232             return ExceptionContinueSearch;
233         case EXCEPTION_CONTINUE_EXECUTION:
234             return ExceptionContinueExecution;
235         case EXCEPTION_EXECUTE_HANDLER:
236             break;
237         default:
238             MESSAGE( "Invalid return value from exception filter\n" );
239             assert( FALSE );
240         }
241     }
242     /* hack to make GetExceptionCode() work in handler */
243     wine_frame->ExceptionCode   = record->ExceptionCode;
244     wine_frame->ExceptionRecord = wine_frame;
245
246     RtlUnwind( frame, 0, record, 0 );
247     EXC_pop_frame( frame );
248     longjmp( wine_frame->jmp, 1 );
249 }
250
251
252 /*************************************************************
253  *            WINE_finally_handler
254  *
255  * Exception handler for try/finally blocks declared in Wine code.
256  */
257 DWORD WINE_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
258                             CONTEXT *context, LPVOID pdispatcher )
259 {
260     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
261
262     if (!(record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
263         return ExceptionContinueSearch;
264     wine_frame->u.finally_func( FALSE );
265     return ExceptionContinueSearch;
266 }