diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 62fbec9a7fc..44790e7bf50 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -8,7 +8,7 @@ #include "debugtools.h" #include "winnt.h" #include "ntddk.h" -#include "except.h" +#include "wine/exception.h" #include "stackframe.h" DEFAULT_DEBUG_CHANNEL(seh) @@ -248,7 +248,7 @@ REGS_ENTRYPOINT(NtRaiseException) first = (BOOL)STACK32_POP(context); STACK32_PUSH(context,ret); /* restore return addr */ - EXC_RaiseException( rec, context ); + EXC_RaiseException( rec, ctx ); *context = *ctx; } @@ -276,9 +276,6 @@ REGS_ENTRYPOINT(RtlRaiseException) /******************************************************************* * RtlUnwind (KERNEL32.590) (NTDLL.518) * - * This function is undocumented. This is the general idea of - * RtlUnwind, though. Note that error handling is not yet implemented. - * * The real prototype is: * void WINAPI RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip, * PEXCEPTION_RECORD pRecord, DWORD returnEax ); diff --git a/if1632/thunk.c b/if1632/thunk.c index 2deebc63e86..ac1b888a4db 100644 --- a/if1632/thunk.c +++ b/if1632/thunk.c @@ -19,7 +19,6 @@ #include "selectors.h" #include "syslevel.h" #include "task.h" -#include "except.h" #include "win.h" #include "flatthunk.h" #include "mouse.h" diff --git a/include/except.h b/include/except.h deleted file mode 100644 index e52b096ef5f..00000000000 --- a/include/except.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * except.h - * Copyright (c) 1996 Onno Hovers (onno@stack.urc.tue.nl) - * Copyright (c) 1999 Alexandre Julliard - */ - -#ifndef __WINE_EXCEPT_H -#define __WINE_EXCEPT_H - -#include -#include "winnt.h" -#include "thread.h" - - -static inline EXCEPTION_FRAME *EXC_push_frame( EXCEPTION_FRAME *frame ) -{ - TEB * teb = NtCurrentTeb(); - frame->Prev = teb->except; - teb->except = frame; - return frame; -} - -static inline EXCEPTION_FRAME *EXC_pop_frame( EXCEPTION_FRAME *frame ) -{ - NtCurrentTeb()->except = frame->Prev; - return frame->Prev; -} - -#endif /* __WINE_EXCEPT_H */ diff --git a/include/wine/exception.h b/include/wine/exception.h new file mode 100644 index 00000000000..06607b4d695 --- /dev/null +++ b/include/wine/exception.h @@ -0,0 +1,128 @@ +/* + * Wine exception handling + * + * Copyright (c) 1999 Alexandre Julliard + */ + +#ifndef __WINE_WINE_EXCEPTION_H +#define __WINE_WINE_EXCEPTION_H + +#include +#include "winnt.h" +#include "thread.h" + +/* The following definitions allow using exceptions in Wine and Winelib code + * + * They should be used like this: + * + * __TRY() + * { + * do some stuff that can raise an exception + * } + * __EXCEPT(filter_func,param) + * { + * handle the exception here + * } + * __ENDTRY() + * + * or + * + * __TRY() + * { + * do some stuff that can raise an exception + * } + * __FINALLY(finally_func,param) + * + * The filter_func must be defined with the WINE_EXCEPTION_FILTER + * macro, and return one of the EXCEPTION_* code; it can use + * GetExceptionInformation and GetExceptionCode to retrieve the + * exception info. + * + * The finally_func must be defined with the WINE_FINALLY_FUNC macro. + * + * Warning: you cannot use return, break, or continue inside a __TRY + * or __EXCEPT block. + * + * -- AJ + */ + +#define __TRY() \ + do { __WINE_FRAME __f; int __state = -1; \ + while (__state != 2) switch(__state) \ + { case 0: /* try */ + +#define __EXCEPT(func,arg) \ + __state = 2; break; \ + case -1: /* init */ \ + __f.frame.Handler = (PEXCEPTION_HANDLER)WINE_exception_handler; \ + __f.u.e.filter = (func); \ + __f.u.e.param = (LPVOID)(arg); \ + EXC_push_frame( &__f.frame ); \ + __state = setjmp( __f.u.e.jmp); \ + break; \ + case 1: /* except */ + +#define __ENDTRY() \ + __state++; break; \ + } \ + EXC_pop_frame( &__f.frame ); \ + } while (0); + +#define __FINALLY(func,arg) \ + __state = 2; break; \ + case -1: /* init */ \ + __f.frame.Handler = (PEXCEPTION_HANDLER)WINE_finally_handler; \ + __f.u.f.finally_func = (func); \ + __f.u.f.param = (LPVOID)(arg); \ + EXC_push_frame( &__f.frame ); \ + __ENDTRY() + +#define WINE_EXCEPTION_FILTER(func,arg) DWORD WINAPI func( EXCEPTION_POINTERS *__eptr, LPVOID arg ) +#define WINE_FINALLY_FUNC(func,arg) void WINAPI func( LPVOID arg ) + +#define GetExceptionInformation() (__eptr) +#define GetExceptionCode() (__eptr->ExceptionRecord->ExceptionCode) + + +typedef DWORD (*CALLBACK __WINE_FILTER)(PEXCEPTION_POINTERS,LPVOID); +typedef void (*CALLBACK __WINE_FINALLY)(LPVOID); + +typedef struct +{ + EXCEPTION_FRAME frame; + union + { + struct /* exception data */ + { + __WINE_FILTER filter; + LPVOID param; + jmp_buf jmp; + } e; + struct /* finally data */ + { + __WINE_FINALLY finally_func; + LPVOID param; + } f; + } u; +} __WINE_FRAME; + +extern DWORD WINAPI WINE_exception_handler( PEXCEPTION_RECORD record, EXCEPTION_FRAME *frame, + CONTEXT *context, LPVOID pdispatcher ); +extern DWORD WINAPI WINE_finally_handler( PEXCEPTION_RECORD record, EXCEPTION_FRAME *frame, + CONTEXT *context, LPVOID pdispatcher ); + +static inline EXCEPTION_FRAME *EXC_push_frame( EXCEPTION_FRAME *frame ) +{ + TEB * teb = NtCurrentTeb(); + frame->Prev = teb->except; + teb->except = frame; + return frame; +} + +static inline EXCEPTION_FRAME *EXC_pop_frame( EXCEPTION_FRAME *frame ) +{ + NtCurrentTeb()->except = frame->Prev; + return frame->Prev; +} + +#endif /* __WINE_WINE_EXCEPTION_H */ diff --git a/win32/except.c b/win32/except.c index 8290a08aca9..26285b41425 100644 --- a/win32/except.c +++ b/win32/except.c @@ -20,27 +20,18 @@ * But exception handling is so basic to Win32 that it should be * documented! * - * Fixmes: - * -Most functions need better parameter checking. - * -I do not know how to handle exceptions within an exception handler. - * or what is done when ExceptionNestedException is returned from an - * exception handler - * -Real exceptions are not yet implemented. only the exception functions - * are implemented. A real implementation needs some new code in - * loader/signal.c. There would also be a need for showing debugging - * information in UnhandledExceptionFilter. - * */ #include #include "winuser.h" #include "winerror.h" +#include "ntddk.h" +#include "wine/exception.h" #include "ldt.h" #include "process.h" #include "thread.h" -#include "debugtools.h" -#include "except.h" #include "stackframe.h" +#include "debugtools.h" DEFAULT_DEBUG_CHANNEL(seh) @@ -107,3 +98,55 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter( pdb->top_filter = filter; return old; } + + +/************************************************************* + * WINE_exception_handler + * + * Exception handler for exception blocks declared in Wine code. + */ +DWORD WINAPI WINE_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, + CONTEXT *context, LPVOID pdispatcher ) +{ + __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; + + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + return ExceptionContinueSearch; + if (wine_frame->u.e.filter) + { + EXCEPTION_POINTERS ptrs; + ptrs.ExceptionRecord = record; + ptrs.ContextRecord = context; + switch(wine_frame->u.e.filter( &ptrs, wine_frame->u.e.param )) + { + case EXCEPTION_CONTINUE_SEARCH: + return ExceptionContinueSearch; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + case EXCEPTION_EXECUTE_HANDLER: + break; + default: + /* FIXME: should probably raise a nested exception here */ + return ExceptionContinueSearch; + } + } + RtlUnwind( frame, 0, record, 0 ); + longjmp( wine_frame->u.e.jmp, 1 ); +} + + +/************************************************************* + * WINE_finally_handler + * + * Exception handler for try/finally blocks declared in Wine code. + */ +DWORD WINAPI WINE_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, + CONTEXT *context, LPVOID pdispatcher ) +{ + __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; + + if (!(record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) + return ExceptionContinueSearch; + wine_frame->u.f.finally_func( wine_frame->u.f.param ); + return ExceptionContinueSearch; +}