Improved exception handling.
Based on the work of Sergey Turchanov <turchanov@usa.net>.

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index db4002d..f8748f4 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -6,6 +6,7 @@
 MODULE    = ntdll
 
 C_SRCS = \
+	exception.c \
 	file.c \
 	nt.c \
 	om.c \
diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
new file mode 100644
index 0000000..62fbec9
--- /dev/null
+++ b/dlls/ntdll/exception.c
@@ -0,0 +1,317 @@
+/*
+ * NT exception handling routines
+ * 
+ * Copyright 1999 Turchanov Sergey
+ * Copyright 1999 Alexandre Julliard
+ */
+
+#include "debugtools.h"
+#include "winnt.h"
+#include "ntddk.h"
+#include "except.h"
+#include "stackframe.h"
+
+DEFAULT_DEBUG_CHANNEL(seh)
+
+/* Exception record for handling exceptions happening inside exception handlers */
+typedef struct
+{
+    EXCEPTION_FRAME frame;
+    EXCEPTION_FRAME *prevFrame;
+} EXC_NESTED_FRAME;
+
+
+/*******************************************************************
+ *         EXC_RaiseHandler
+ *
+ * Handler for exceptions happening inside a handler.
+ */
+static DWORD CALLBACK EXC_RaiseHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
+                                        CONTEXT *context, EXCEPTION_FRAME **dispatcher )
+{
+    if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
+        return ExceptionContinueSearch;
+    /* We shouldn't get here so we store faulty frame in dispatcher */
+    *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
+    return ExceptionNestedException;
+}
+
+
+/*******************************************************************
+ *         EXC_UnwindHandler
+ *
+ * Handler for exceptions happening inside an unwind handler.
+ */
+static DWORD CALLBACK EXC_UnwindHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
+                                         CONTEXT *context, EXCEPTION_FRAME **dispatcher )
+{
+    if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
+        return ExceptionContinueSearch;
+    /* We shouldn't get here so we store faulty frame in dispatcher */
+    *dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
+    return ExceptionCollidedUnwind;
+}
+
+
+/*******************************************************************
+ *         EXC_CallHandler
+ *
+ * Call an exception handler, setting up an exception frame to catch exceptions
+ * happening during the handler execution.
+ */
+static DWORD EXC_CallHandler( PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler,
+                              EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
+                              CONTEXT *context, EXCEPTION_FRAME **dispatcher )
+{
+    EXC_NESTED_FRAME newframe;
+    DWORD ret;
+
+    newframe.frame.Handler = nested_handler;
+    newframe.prevFrame     = frame;
+    EXC_push_frame( &newframe.frame );
+    TRACE( "calling handler at %p\n", handler );
+    ret = handler( record, frame, context, dispatcher );
+    TRACE( "handler returned %lx\n", ret );
+    EXC_pop_frame( &newframe.frame );
+    return ret;
+}
+
+
+/*******************************************************************
+ *         EXC_DefaultHandling
+ *
+ * Default handling for exceptions. Called when we didn't find a suitable handler.
+ */
+static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    if (rec->ExceptionFlags & EH_STACK_INVALID)
+        ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
+    else if (rec->ExceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION)
+        ERR("Process attempted to continue execution after noncontinuable exception.\n");
+    else
+        ERR("Unhandled exception code %lx flags %lx addr %p\n",
+            rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
+    /* Should I add here a back trace ? */
+    TerminateProcess( GetCurrentProcess(), 1 );
+}
+
+
+/*******************************************************************
+ *         EXC_RaiseException
+ *
+ * Implementation of NtRaiseException.
+ */
+static void EXC_RaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    PEXCEPTION_FRAME frame, dispatch, nested_frame;
+    EXCEPTION_RECORD newrec;
+    DWORD res;
+
+    frame = NtCurrentTeb()->except;
+    nested_frame = NULL;
+    while (frame != (PEXCEPTION_FRAME)0xFFFFFFFF)
+    {
+        /* Check frame address */
+        if (((void*)frame < NtCurrentTeb()->stack_low) ||
+            ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
+            (int)frame & 3)
+        {
+            rec->ExceptionFlags |= EH_STACK_INVALID;
+            break;
+        }
+
+        /* Call handler */
+        res = EXC_CallHandler( frame->Handler, EXC_RaiseHandler, rec, frame, context, &dispatch );
+        if (frame == nested_frame)
+        {
+            /* no longer nested */
+            nested_frame = NULL;
+            rec->ExceptionFlags &= ~EH_NESTED_CALL;
+        }
+
+        switch(res)
+        {
+        case ExceptionContinueExecution:
+            if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return;
+            newrec.ExceptionCode    = STATUS_NONCONTINUABLE_EXCEPTION;
+            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
+            newrec.ExceptionRecord  = rec;
+            newrec.NumberParameters = 0;
+            RtlRaiseException( &newrec );  /* never returns */
+            break;
+        case ExceptionContinueSearch:
+            break;
+        case ExceptionNestedException:
+            if (nested_frame < dispatch) nested_frame = dispatch;
+            rec->ExceptionFlags |= EH_NESTED_CALL;
+            break;
+        default:
+            newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
+            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
+            newrec.ExceptionRecord  = rec;
+            newrec.NumberParameters = 0;
+            RtlRaiseException( &newrec );  /* never returns */
+            break;
+        }
+        frame = frame->Prev;
+    }
+    EXC_DefaultHandling( rec, context );
+}
+
+
+/*******************************************************************
+ *         EXC_RtlUnwind
+ *
+ * Implementation of RtlUnwind.
+ */
+static void EXC_RtlUnwind( EXCEPTION_FRAME *pEndFrame, EXCEPTION_RECORD *pRecord,
+                           CONTEXT *context )
+{
+    EXCEPTION_RECORD record, newrec;
+    PEXCEPTION_FRAME frame, dispatch;
+
+    /* build an exception record, if we do not have one */
+    if (!pRecord)
+    {
+        record.ExceptionCode    = STATUS_UNWIND;
+        record.ExceptionFlags   = 0;
+        record.ExceptionRecord  = NULL;
+        record.ExceptionAddress = (LPVOID)EIP_reg(context); 
+        record.NumberParameters = 0;
+        pRecord = &record;
+    }
+
+    pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
+  
+    /* get chain of exception frames */
+    frame = NtCurrentTeb()->except;
+    while ((frame != (PEXCEPTION_FRAME)0xffffffff) && (frame != pEndFrame))
+    {
+        /* Check frame address */
+        if (pEndFrame && (frame > pEndFrame))
+        {
+            newrec.ExceptionCode    = STATUS_INVALID_UNWIND_TARGET;
+            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
+            newrec.ExceptionRecord  = pRecord;
+            newrec.NumberParameters = 0;
+            RtlRaiseException( &newrec );  /* never returns */
+        }
+        if (((void*)frame < NtCurrentTeb()->stack_low) ||
+            ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
+            (int)frame & 3)
+        {
+            newrec.ExceptionCode    = STATUS_BAD_STACK;
+            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
+            newrec.ExceptionRecord  = pRecord;
+            newrec.NumberParameters = 0;
+            RtlRaiseException( &newrec );  /* never returns */
+        }
+
+        /* Call handler */
+        switch(EXC_CallHandler( frame->Handler, EXC_UnwindHandler, pRecord,
+                                frame, context, &dispatch ))
+        {
+        case ExceptionContinueSearch:
+            break;
+        case ExceptionCollidedUnwind:
+            frame = dispatch;
+            break;
+        default:
+            newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
+            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
+            newrec.ExceptionRecord  = pRecord;
+            newrec.NumberParameters = 0;
+            RtlRaiseException( &newrec );  /* never returns */
+            break;
+        }
+        NtCurrentTeb()->except = frame = frame->Prev;
+    }
+}
+
+
+/*******************************************************************
+ *         NtRaiseException    (NTDLL.175)
+ *
+ * Real prototype:
+ *    DWORD WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *ctx, BOOL first );
+ */
+REGS_ENTRYPOINT(NtRaiseException)
+{
+    DWORD ret;
+    EXCEPTION_RECORD *rec;
+    CONTEXT *ctx;
+    BOOL first;
+
+    ret   = STACK32_POP(context);  /* return addr */
+    rec   = (PEXCEPTION_RECORD)STACK32_POP(context);
+    ctx   = (PCONTEXT)STACK32_POP(context);
+    first = (BOOL)STACK32_POP(context);
+    STACK32_PUSH(context,ret);  /* restore return addr */
+
+    EXC_RaiseException( rec, context );
+    *context = *ctx;
+}
+
+
+/***********************************************************************
+ *            RtlRaiseException  (NTDLL.464)
+ *
+ * Real prototype:
+ *     void WINAPI RtlRaiseException(PEXCEPTION_RECORD pRecord)
+ */
+REGS_ENTRYPOINT(RtlRaiseException)
+{
+    EXCEPTION_RECORD *rec;
+    DWORD ret;
+
+    ret = STACK32_POP(context);  /* return addr */
+    rec = (PEXCEPTION_RECORD)STACK32_POP(context);
+    STACK32_PUSH(context,ret);  /* restore return addr */
+
+    rec->ExceptionAddress = (LPVOID)EIP_reg(context);
+    EXC_RaiseException( rec, context );
+}
+
+
+/*******************************************************************
+ *         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 );
+ */
+REGS_ENTRYPOINT(RtlUnwind)
+{
+    PEXCEPTION_FRAME pEndFrame;
+    PEXCEPTION_RECORD pRecord;
+
+    /* get the arguments from the stack */
+    DWORD ret        = STACK32_POP(context);  /* return addr */
+    pEndFrame        = (PEXCEPTION_FRAME)STACK32_POP(context);
+    (void)STACK32_POP(context);  /* unused arg */
+    pRecord          = (PEXCEPTION_RECORD)STACK32_POP(context);
+    EAX_reg(context) = STACK32_POP(context);
+    STACK32_PUSH(context,ret);  /* restore return addr */
+
+    EXC_RtlUnwind( pEndFrame, pRecord, context );
+}
+
+
+/***********************************************************************
+ *            RtlRaiseStatus  (NTDLL.465)
+ *
+ * Raise an exception with ExceptionCode = status
+ */
+void WINAPI RtlRaiseStatus( NTSTATUS status )
+{
+    EXCEPTION_RECORD ExceptionRec;
+
+    ExceptionRec.ExceptionCode    = status;
+    ExceptionRec.ExceptionFlags   = EH_NONCONTINUABLE;
+    ExceptionRec.ExceptionRecord  = NULL;
+    ExceptionRec.NumberParameters = 0;
+    RtlRaiseException( &ExceptionRec );
+}
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c
index d0c8c93..931bf97 100644
--- a/dlls/ntdll/rtl.c
+++ b/dlls/ntdll/rtl.c
@@ -283,15 +283,7 @@
 	MSG("DbgPrint says: %s",buf);
 	/* hmm, raise exception? */
 }
-DWORD NtRaiseException ( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments)
-{	FIXME(ntdll,"0x%08lx 0x%08lx 0x%08lx %p\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
-	return 0;
-}
 
-DWORD RtlRaiseException ( DWORD x)
-{	FIXME(ntdll, "0x%08lx\n", x);
-	return 0;
-}
 /******************************************************************************
  *  RtlAcquirePebLock		[NTDLL] 
  */
diff --git a/include/debugdefs.h b/include/debugdefs.h
index 78c8599..652ba91 100644
--- a/include/debugdefs.h
+++ b/include/debugdefs.h
@@ -122,50 +122,51 @@
 int dbch_scroll = 111;
 int dbch_security = 112;
 int dbch_segment = 113;
-int dbch_selector = 114;
-int dbch_sem = 115;
-int dbch_sendmsg = 116;
-int dbch_server = 117;
-int dbch_shell = 118;
-int dbch_shm = 119;
-int dbch_snoop = 120;
-int dbch_sound = 121;
-int dbch_static = 122;
-int dbch_statusbar = 123;
-int dbch_storage = 124;
-int dbch_stress = 125;
-int dbch_string = 126;
-int dbch_syscolor = 127;
-int dbch_system = 128;
-int dbch_tab = 129;
-int dbch_tapi = 130;
-int dbch_task = 131;
-int dbch_text = 132;
-int dbch_thread = 133;
-int dbch_thunk = 134;
-int dbch_timer = 135;
-int dbch_toolbar = 136;
-int dbch_toolhelp = 137;
-int dbch_tooltips = 138;
-int dbch_trackbar = 139;
-int dbch_treeview = 140;
-int dbch_ttydrv = 141;
-int dbch_tweak = 142;
-int dbch_updown = 143;
-int dbch_ver = 144;
-int dbch_virtual = 145;
-int dbch_vxd = 146;
-int dbch_wave = 147;
-int dbch_win = 148;
-int dbch_win16drv = 149;
-int dbch_win32 = 150;
-int dbch_wing = 151;
-int dbch_winsock = 152;
-int dbch_wnet = 153;
-int dbch_x11 = 154;
-int dbch_x11drv = 155;
+int dbch_seh = 114;
+int dbch_selector = 115;
+int dbch_sem = 116;
+int dbch_sendmsg = 117;
+int dbch_server = 118;
+int dbch_shell = 119;
+int dbch_shm = 120;
+int dbch_snoop = 121;
+int dbch_sound = 122;
+int dbch_static = 123;
+int dbch_statusbar = 124;
+int dbch_storage = 125;
+int dbch_stress = 126;
+int dbch_string = 127;
+int dbch_syscolor = 128;
+int dbch_system = 129;
+int dbch_tab = 130;
+int dbch_tapi = 131;
+int dbch_task = 132;
+int dbch_text = 133;
+int dbch_thread = 134;
+int dbch_thunk = 135;
+int dbch_timer = 136;
+int dbch_toolbar = 137;
+int dbch_toolhelp = 138;
+int dbch_tooltips = 139;
+int dbch_trackbar = 140;
+int dbch_treeview = 141;
+int dbch_ttydrv = 142;
+int dbch_tweak = 143;
+int dbch_updown = 144;
+int dbch_ver = 145;
+int dbch_virtual = 146;
+int dbch_vxd = 147;
+int dbch_wave = 148;
+int dbch_win = 149;
+int dbch_win16drv = 150;
+int dbch_win32 = 151;
+int dbch_wing = 152;
+int dbch_winsock = 153;
+int dbch_wnet = 154;
+int dbch_x11 = 155;
+int dbch_x11drv = 156;
 
-#define DEBUG_CHANNEL_COUNT 156
+#define DEBUG_CHANNEL_COUNT 157
 
 char __debug_msg_enabled[DEBUG_CHANNEL_COUNT][DEBUG_CLASS_COUNT] = {
 {1, 1, 0, 0},
@@ -323,6 +324,7 @@
 {1, 1, 0, 0},
 {1, 1, 0, 0},
 {1, 1, 0, 0},
+{1, 1, 0, 0},
 {1, 1, 0, 0}
 };
 
@@ -441,6 +443,7 @@
 "scroll",
 "security",
 "segment",
+"seh",
 "selector",
 "sem",
 "sendmsg",
diff --git a/include/except.h b/include/except.h
index c954177..979fb0c 100644
--- a/include/except.h
+++ b/include/except.h
@@ -1,12 +1,15 @@
 /*
  * except.h
- * Copyright (c) 1996, Onno Hovers (onno@stack.urc.tue.nl)
+ * Copyright (c) 1996 Onno Hovers (onno@stack.urc.tue.nl)
+ * Copyright (c) 1999 Alexandre Julliard
  */
 
 #ifndef __WINE_EXCEPT_H
 #define __WINE_EXCEPT_H
 
+#include <setjmp.h>
 #include "winnt.h"
+#include "thread.h"
 
 /*
  * the function pointer to a exception handler
@@ -18,7 +21,7 @@
 typedef DWORD (CALLBACK *PEXCEPTION_HANDLER)( PEXCEPTION_RECORD pexcrec,
                                       struct __EXCEPTION_FRAME  *pestframe,
                                       PCONTEXT                   pcontext,
-                                      LPVOID                     pdispatcher);
+                                      struct __EXCEPTION_FRAME **pdispatcher);
 
 /*
  * The exception frame, used for registering exception handlers 
@@ -33,22 +36,20 @@
 } EXCEPTION_FRAME, *PEXCEPTION_FRAME;
 
                         
-/*
- *  this undocumented function is called when an exception
- *  handler wants all the frames to be unwound. RtlUnwind
- *  calls all exception handlers with the EH_UNWIND or
- *  EH_EXIT_UNWIND flags set in the exception record
- *
- *  This prototype assumes RtlUnwind takes the same
- *  parameters as OS/2 2.0 DosUnwindException
- *  Disassembling RtlUnwind shows this is true, except for
- *  the TargetEIP parameter, which is unused. There is 
- *  a fourth parameter, that is used as the eax in the 
- *  context.   
- */
-void WINAPI RtlUnwind( PEXCEPTION_FRAME pestframe,
-                       LPVOID unusedEIP,
-                       PEXCEPTION_RECORD pexcrec,
-                       DWORD contextEAX );
+void WINAPI RtlUnwind(PEXCEPTION_FRAME,LPVOID,PEXCEPTION_RECORD,DWORD);
+
+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/ntddk.h b/include/ntddk.h
index 898b1f4..4d19e40 100644
--- a/include/ntddk.h
+++ b/include/ntddk.h
@@ -573,8 +573,8 @@
  *	misc
  */
 void __cdecl DbgPrint(LPCSTR fmt,LPVOID args);
-DWORD NtRaiseException ( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments);
-DWORD RtlRaiseException ( DWORD x);
+DWORD WINAPI NtRaiseException(PEXCEPTION_RECORD,PCONTEXT,BOOL);
+void WINAPI RtlRaiseException(PEXCEPTION_RECORD);
 VOID WINAPI RtlAcquirePebLock(void);
 VOID WINAPI RtlReleasePebLock(void);
 DWORD WINAPI RtlAdjustPrivilege(DWORD x1,DWORD x2,DWORD x3,DWORD x4);
diff --git a/include/thread.h b/include/thread.h
index c0595ff..9cd30a8 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -12,11 +12,12 @@
 #include "selectors.h"  /* for SET_FS */
 
 struct _PDB;
+struct __EXCEPTION_FRAME;
 
 /* Thread exception block */
 typedef struct _TEB
 {
-    void        *except;         /* 00 Head of exception handling chain */
+    struct __EXCEPTION_FRAME *except; /* 00 Head of exception handling chain */
     void        *stack_top;      /* 04 Top of thread stack */
     void        *stack_low;      /* 08 Stack low-water mark */
     HTASK16      htask16;        /* 0c Win16 task handle */
diff --git a/include/winbase.h b/include/winbase.h
index d9bfe56..419ed96 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -992,42 +992,30 @@
 #define FS_CASE_IS_PRESERVED            FILE_CASE_PRESERVED_NAMES
 #define FS_UNICODE_STORED_ON_DISK       FILE_UNICODE_ON_DISK
 
+#define EXCEPTION_ACCESS_VIOLATION          STATUS_ACCESS_VIOLATION
+#define EXCEPTION_DATATYPE_MISALIGNMENT     STATUS_DATATYPE_MISALIGNMENT
+#define EXCEPTION_BREAKPOINT                STATUS_BREAKPOINT
+#define EXCEPTION_SINGLE_STEP               STATUS_SINGLE_STEP
+#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED     STATUS_ARRAY_BOUNDS_EXCEEDED
+#define EXCEPTION_FLT_DENORMAL_OPERAND      STATUS_FLOAT_DENORMAL_OPERAND
+#define EXCEPTION_FLT_DIVIDE_BY_ZERO        STATUS_FLOAT_DIVIDE_BY_ZERO
+#define EXCEPTION_FLT_INEXACT_RESULT        STATUS_FLOAT_INEXACT_RESULT
+#define EXCEPTION_FLT_INVALID_OPERATION     STATUS_FLOAT_INVALID_OPERATION
+#define EXCEPTION_FLT_OVERFLOW              STATUS_FLOAT_OVERFLOW
+#define EXCEPTION_FLT_STACK_CHECK           STATUS_FLOAT_STACK_CHECK
+#define EXCEPTION_FLT_UNDERFLOW             STATUS_FLOAT_UNDERFLOW
+#define EXCEPTION_INT_DIVIDE_BY_ZERO        STATUS_INTEGER_DIVIDE_BY_ZERO
+#define EXCEPTION_INT_OVERFLOW              STATUS_INTEGER_OVERFLOW
+#define EXCEPTION_PRIV_INSTRUCTION          STATUS_PRIVILEGED_INSTRUCTION
+#define EXCEPTION_IN_PAGE_ERROR             STATUS_IN_PAGE_ERROR
+#define EXCEPTION_ILLEGAL_INSTRUCTION       STATUS_ILLEGAL_INSTRUCTION
+#define EXCEPTION_NONCONTINUABLE_EXCEPTION  STATUS_NONCONTINUABLE_EXCEPTION
+#define EXCEPTION_STACK_OVERFLOW            STATUS_STACK_OVERFLOW
+#define EXCEPTION_INVALID_DISPOSITION       STATUS_INVALID_DISPOSITION
+#define EXCEPTION_GUARD_PAGE                STATUS_GUARD_PAGE_VIOLATION
+#define EXCEPTION_INVALID_HANDLE            STATUS_INVALID_HANDLE
+#define CONTROL_C_EXIT                      STATUS_CONTROL_C_EXIT
 
-#define STATUS_SUCCESS                   0x00000000
-#define STATUS_WAIT_0                    0x00000000    
-#define STATUS_ABANDONED_WAIT_0          0x00000080    
-#define STATUS_USER_APC                  0x000000C0    
-#define STATUS_TIMEOUT                   0x00000102    
-#define STATUS_PENDING                   0x00000103    
-#define STATUS_GUARD_PAGE_VIOLATION      0x80000001    
-#define STATUS_DATATYPE_MISALIGNMENT     0x80000002    
-#define STATUS_BREAKPOINT                0x80000003    
-#define STATUS_SINGLE_STEP               0x80000004    
-#define	STATUS_BUFFER_OVERFLOW           0x80000005
-#define STATUS_ACCESS_VIOLATION          0xC0000005    
-#define STATUS_IN_PAGE_ERROR             0xC0000006    
-#define STATUS_INVALID_PARAMETER         0xC000000D
-#define STATUS_NO_MEMORY                 0xC0000017    
-#define STATUS_ILLEGAL_INSTRUCTION       0xC000001D    
-#define	STATUS_BUFFER_TOO_SMALL          0xC0000023
-#define STATUS_NONCONTINUABLE_EXCEPTION  0xC0000025    
-#define STATUS_INVALID_DISPOSITION       0xC0000026    
-#define	STATUS_UNKNOWN_REVISION          0xC0000058
-#define	STATUS_INVALID_SECURITY_DESCR    0xC0000079
-#define STATUS_ARRAY_BOUNDS_EXCEEDED     0xC000008C    
-#define STATUS_FLOAT_DENORMAL_OPERAND    0xC000008D    
-#define STATUS_FLOAT_DIVIDE_BY_ZERO      0xC000008E    
-#define STATUS_FLOAT_INEXACT_RESULT      0xC000008F    
-#define STATUS_FLOAT_INVALID_OPERATION   0xC0000090    
-#define STATUS_FLOAT_OVERFLOW            0xC0000091    
-#define STATUS_FLOAT_STACK_CHECK         0xC0000092    
-#define STATUS_FLOAT_UNDERFLOW           0xC0000093    
-#define STATUS_INTEGER_DIVIDE_BY_ZERO    0xC0000094    
-#define STATUS_INTEGER_OVERFLOW          0xC0000095    
-#define STATUS_PRIVILEGED_INSTRUCTION    0xC0000096    
-#define	STATUS_INVALID_PARAMETER_2       0xC00000F0
-#define STATUS_STACK_OVERFLOW            0xC00000FD    
-#define STATUS_CONTROL_C_EXIT            0xC000013A    
 
 #define DUPLICATE_CLOSE_SOURCE		0x00000001
 #define DUPLICATE_SAME_ACCESS		0x00000002
@@ -1046,29 +1034,6 @@
 #define THREAD_PRIORITY_TIME_CRITICAL   THREAD_BASE_PRIORITY_LOWRT
 #define THREAD_PRIORITY_IDLE            THREAD_BASE_PRIORITY_IDLE
 
-typedef struct 
-{
-  int type;
-} wine_exception;
-
-typedef struct 
-{
-  int pad[39];
-  int edi;
-  int esi;
-  int ebx;
-  int edx;
-  int ecx;
-  int eax;
-
-  int ebp;
-  int eip;
-  int cs;
-  int eflags;
-  int esp;
-  int ss;
-} exception_info;
-
 /* Could this type be considered opaque? */
 typedef struct {
 	LPVOID	DebugInfo;
diff --git a/include/winnt.h b/include/winnt.h
index a99763f..a05415bd 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -216,20 +216,32 @@
  * Exception codes
  */
  
+#define STATUS_SUCCESS                   0x00000000
 #define STATUS_WAIT_0                    0x00000000
 #define STATUS_ABANDONED_WAIT_0          0x00000080
 #define STATUS_USER_APC                  0x000000C0
 #define STATUS_TIMEOUT                   0x00000102
 #define STATUS_PENDING                   0x00000103
+#define STATUS_GUARD_PAGE_VIOLATION      0x80000001    
 #define STATUS_DATATYPE_MISALIGNMENT     0x80000002
 #define STATUS_BREAKPOINT                0x80000003
 #define STATUS_SINGLE_STEP               0x80000004
+#define	STATUS_BUFFER_OVERFLOW           0x80000005
+#define STATUS_UNSUCCESSFUL              0xC0000001
 #define STATUS_ACCESS_VIOLATION          0xC0000005
 #define STATUS_IN_PAGE_ERROR             0xC0000006
+#define STATUS_INVALID_PARAMETER         0xC000000D
 #define STATUS_NO_MEMORY                 0xC0000017
+#define STATUS_CONFLICTING_ADDRESSES     0xC0000018
 #define STATUS_ILLEGAL_INSTRUCTION       0xC000001D
+#define	STATUS_BUFFER_TOO_SMALL          0xC0000023
 #define STATUS_NONCONTINUABLE_EXCEPTION  0xC0000025
 #define STATUS_INVALID_DISPOSITION       0xC0000026
+#define STATUS_UNWIND                    0xC0000027
+#define STATUS_BAD_STACK                 0xC0000028
+#define STATUS_INVALID_UNWIND_TARGET     0xC0000029
+#define	STATUS_UNKNOWN_REVISION          0xC0000058
+#define	STATUS_INVALID_SECURITY_DESCR    0xC0000079
 #define STATUS_ARRAY_BOUNDS_EXCEEDED     0xC000008C
 #define STATUS_FLOAT_DENORMAL_OPERAND    0xC000008D
 #define STATUS_FLOAT_DIVIDE_BY_ZERO      0xC000008E
@@ -241,33 +253,10 @@
 #define STATUS_INTEGER_DIVIDE_BY_ZERO    0xC0000094
 #define STATUS_INTEGER_OVERFLOW          0xC0000095
 #define STATUS_PRIVILEGED_INSTRUCTION    0xC0000096
+#define	STATUS_INVALID_PARAMETER_2       0xC00000F0
 #define STATUS_STACK_OVERFLOW            0xC00000FD
 #define STATUS_CONTROL_C_EXIT            0xC000013A
 
-#define EXCEPTION_ACCESS_VIOLATION          STATUS_ACCESS_VIOLATION
-#define EXCEPTION_DATATYPE_MISALIGNMENT     STATUS_DATATYPE_MISALIGNMENT
-#define EXCEPTION_BREAKPOINT                STATUS_BREAKPOINT
-#define EXCEPTION_SINGLE_STEP               STATUS_SINGLE_STEP
-#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED     STATUS_ARRAY_BOUNDS_EXCEEDED
-#define EXCEPTION_FLT_DENORMAL_OPERAND      STATUS_FLOAT_DENORMAL_OPERAND
-#define EXCEPTION_FLT_DIVIDE_BY_ZERO        STATUS_FLOAT_DIVIDE_BY_ZERO
-#define EXCEPTION_FLT_INEXACT_RESULT        STATUS_FLOAT_INEXACT_RESULT
-#define EXCEPTION_FLT_INVALID_OPERATION     STATUS_FLOAT_INVALID_OPERATION
-#define EXCEPTION_FLT_OVERFLOW              STATUS_FLOAT_OVERFLOW
-#define EXCEPTION_FLT_STACK_CHECK           STATUS_FLOAT_STACK_CHECK
-#define EXCEPTION_FLT_UNDERFLOW             STATUS_FLOAT_UNDERFLOW
-#define EXCEPTION_INT_DIVIDE_BY_ZERO        STATUS_INTEGER_DIVIDE_BY_ZERO
-#define EXCEPTION_INT_OVERFLOW              STATUS_INTEGER_OVERFLOW
-#define EXCEPTION_PRIV_INSTRUCTION          STATUS_PRIVILEGED_INSTRUCTION
-#define EXCEPTION_IN_PAGE_ERROR             STATUS_IN_PAGE_ERROR
-#define EXCEPTION_ILLEGAL_INSTRUCTION       STATUS_ILLEGAL_INSTRUCTION
-#define EXCEPTION_NONCONTINUABLE_EXCEPTION  STATUS_NONCONTINUABLE_EXCEPTION
-#define EXCEPTION_STACK_OVERFLOW            STATUS_STACK_OVERFLOW
-#define EXCEPTION_INVALID_DISPOSITION       STATUS_INVALID_DISPOSITION
-#define EXCEPTION_GUARD_PAGE                STATUS_GUARD_PAGE_VIOLATION
-#define EXCEPTION_INVALID_HANDLE            STATUS_INVALID_HANDLE
-#define CONTROL_C_EXIT                      STATUS_CONTROL_C_EXIT
-
 #define MAXIMUM_WAIT_OBJECTS 64
 #define MAXIMUM_SUSPEND_COUNT 127
 
diff --git a/relay32/kernel32.spec b/relay32/kernel32.spec
index 4375e1d..e736395 100644
--- a/relay32/kernel32.spec
+++ b/relay32/kernel32.spec
@@ -582,7 +582,7 @@
 564 stdcall QueryPerformanceCounter(ptr) QueryPerformanceCounter
 565 stdcall QueryPerformanceFrequency(ptr) QueryPerformanceFrequency
 566 stdcall QueueUserAPC(ptr long long) QueueUserAPC
-567 register RaiseException() RaiseException
+567 stdcall RaiseException(long long long ptr) RaiseException
 568 stdcall ReadConsoleA(long ptr long ptr ptr) ReadConsoleA
 569 stdcall ReadConsoleInputA(long ptr long ptr) ReadConsoleInputA
 570 stdcall ReadConsoleInputW(long ptr long ptr) ReadConsoleInputW 
diff --git a/relay32/ntdll.spec b/relay32/ntdll.spec
index 8dabefb..9207683 100644
--- a/relay32/ntdll.spec
+++ b/relay32/ntdll.spec
@@ -180,7 +180,7 @@
 172 stdcall NtQueryValueKey(long long long long long long) NtQueryValueKey
 173 stub NtQueryVirtualMemory
 174 stub NtQueryVolumeInformationFile
-175 stdcall NtRaiseException(long long long ptr) NtRaiseException
+175 register NtRaiseException() NtRaiseException
 176 stub NtRaiseHardError
 177 stdcall NtReadFile(long long long long long long long long long) NtReadFile
 178 stub NtReadRequestData
@@ -469,8 +469,8 @@
 461 stub RtlQuerySecurityObject
 462 stub RtlQueryTagHeap
 463 stub RtlQueryTimeZoneInformation
-464 stdcall RtlRaiseException (long) RtlRaiseException
-465 stub RtlRaiseStatus
+464 register RtlRaiseException() RtlRaiseException
+465 stdcall RtlRaiseStatus(long) RtlRaiseStatus
 466 stub RtlRandom
 467 stub RtlReAllocateHeap
 468 stub RtlRealPredecessor
diff --git a/win32/except.c b/win32/except.c
index 8750bd2..8290a08 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -2,6 +2,7 @@
  * Win32 exception functions
  *
  * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
+ * Copyright (c) 1999 Alexandre Julliard
  *
  * Notes:
  *  What really happens behind the scenes of those new
@@ -41,152 +42,31 @@
 #include "except.h"
 #include "stackframe.h"
 
-DECLARE_DEBUG_CHANNEL(relay)
-DECLARE_DEBUG_CHANNEL(win32)
-
-#define TEB_EXCEPTION_FRAME(pcontext) \
-    ((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
-
-/*******************************************************************
- *         RtlUnwind  (KERNEL32.443)
- *
- *  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 EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip, 
- *                            PEXCEPTION_RECORD pRecord, DWORD returnEax );
- */
-REGS_ENTRYPOINT(RtlUnwind)
-{
-    EXCEPTION_RECORD record;
-    DWORD            dispatch;
-    int              retval;
-    PEXCEPTION_FRAME pEndFrame;
-    PEXCEPTION_RECORD pRecord;
-
-    /* get the arguments from the stack */
-
-    DWORD ret        = STACK32_POP(context);  /* return addr */
-    pEndFrame        = (PEXCEPTION_FRAME)STACK32_POP(context);
-    (void)STACK32_POP(context);  /* unused arg */
-    pRecord          = (PEXCEPTION_RECORD)STACK32_POP(context);
-    EAX_reg(context) = STACK32_POP(context);
-    STACK32_PUSH(context,ret);  /* restore return addr */
-   
-   /* build an exception record, if we do not have one */
-   if(!pRecord)
-   {
-     record.ExceptionCode    = STATUS_INVALID_DISPOSITION;
-     record.ExceptionFlags   = 0;
-     record.ExceptionRecord  = NULL;
-     record.ExceptionAddress = (LPVOID)EIP_reg(context); 
-     record.NumberParameters = 0;
-     pRecord = &record;
-   }
-
-   if(pEndFrame)
-     pRecord->ExceptionFlags|=EH_UNWINDING;
-   else
-     pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
-  
-   /* get chain of exception frames */      
-   while ((TEB_EXCEPTION_FRAME(context) != NULL) &&
-          (TEB_EXCEPTION_FRAME(context) != ((void *)0xffffffff)) &&
-          (TEB_EXCEPTION_FRAME(context) != pEndFrame))
-   {
-       TRACE_(win32)("calling exception handler at 0x%x\n",
-                      (int)TEB_EXCEPTION_FRAME(context)->Handler );
-
-       dispatch=0;       
-       retval = TEB_EXCEPTION_FRAME(context)->Handler( pRecord,
-                                                TEB_EXCEPTION_FRAME(context),
-                                                context, &dispatch);
-                                         
-       TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
-                              retval, (int) dispatch);
-  
-       if (	(retval == ExceptionCollidedUnwind) &&
-           	(TEB_EXCEPTION_FRAME(context) != (LPVOID)dispatch)
-       )
-           TEB_EXCEPTION_FRAME(context) = (LPVOID)dispatch;
-       else if (	(TEB_EXCEPTION_FRAME(context) != pEndFrame) &&
-           		(TEB_EXCEPTION_FRAME(context) != TEB_EXCEPTION_FRAME(context)->Prev)
-       )
-           TEB_EXCEPTION_FRAME(context) = TEB_EXCEPTION_FRAME(context)->Prev;
-       else
-          break;  
-   }
-}
+DEFAULT_DEBUG_CHANNEL(seh)
 
 
 /*******************************************************************
  *         RaiseException  (KERNEL32.418)
- *
- * The real prototype is:
- * void WINAPI EXC_RaiseException(DWORD dwExceptionCode,
- *                                DWORD dwExceptionFlags,
- *                                DWORD cArguments,
- *                                const LPDWORD lpArguments );
  */
-REGS_ENTRYPOINT(RaiseException)
+void WINAPI RaiseException( DWORD code, DWORD flags, DWORD nbargs, const LPDWORD args )
 {
-    PEXCEPTION_FRAME    pframe; 
-    EXCEPTION_RECORD    record;
-    DWORD               dispatch; /* is this used in raising exceptions ?? */
-    int                 retval;
-    int                 i;
+    EXCEPTION_RECORD record;
 
-    /* Get the arguments from the stack */
-
-    DWORD ret                 = STACK32_POP(context);  /* return addr */
-    DWORD dwExceptionCode     = STACK32_POP(context);
-    DWORD dwExceptionFlags    = STACK32_POP(context);
-    DWORD cArguments          = STACK32_POP(context);
-    const LPDWORD lpArguments = (LPDWORD)STACK32_POP(context);
-    STACK32_PUSH(context,ret);  /* Restore the return address */
-
-    /* compose an exception record */ 
+    /* Compose an exception record */ 
     
-    record.ExceptionCode       = dwExceptionCode;   
-    record.ExceptionFlags      = dwExceptionFlags;
-    record.ExceptionRecord     = NULL;
-    record.NumberParameters    = cArguments;
-    record.ExceptionAddress    = (LPVOID)EIP_reg(context);
-    
-    if (lpArguments) for( i = 0; i < cArguments; i++)
-        record.ExceptionInformation[i] = lpArguments[i];
-    
-    /* get chain of exception frames */    
-    
-    retval = ExceptionContinueSearch;    
-    pframe = TEB_EXCEPTION_FRAME( context );
-    
-    while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
+    record.ExceptionCode    = code;
+    record.ExceptionFlags   = flags & EH_NONCONTINUABLE;
+    record.ExceptionRecord  = NULL;
+    record.ExceptionAddress = RaiseException;
+    if (nbargs && args)
     {
-       PEXCEPTION_FRAME    prevframe; 
-       TRACE_(win32)("calling exception handler at 0x%x\n",
-                                                (int) pframe->Handler);
-       dispatch=0;  
-       TRACE_(relay)("(except=%p,record=%p,frame=%p,context=%p,dispatch=%p)\n",
-                     pframe->Handler, &record, pframe, context, &dispatch );
-       prevframe = pframe->Prev;
-       retval=pframe->Handler(&record,pframe,context,&dispatch);
- 
-       TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
-                              retval, (int) dispatch);
-                              
-       if(retval==ExceptionContinueExecution)
-          break;
-       pframe=prevframe;
-   }
+        if (nbargs > EXCEPTION_MAXIMUM_PARAMETERS) nbargs = EXCEPTION_MAXIMUM_PARAMETERS;
+        record.NumberParameters = nbargs;
+        memcpy( record.ExceptionInformation, args, nbargs * sizeof(*args) );
+    }
+    else record.NumberParameters = 0;
 
-   if (retval!=ExceptionContinueExecution)
-   {    
-       /* FIXME: what should we do here? */
-       TRACE_(win32)("no handler wanted to handle the exception, exiting\n");
-       ExitProcess(dwExceptionCode); /* what status should be used here ? */
-   }
+    RtlRaiseException( &record );
 }