ntdll: Extend exception filters and finally functions to allow a parameter.

Dan Hipschman dsh at linux.ucla.edu
Fri Nov 9 18:04:32 CST 2007


The widl-generated proxy code needs to be able to handle exceptions, so
the next patch adds a --wine-seh option to widl to handle them using Wine's
__TRY / __EXCEPT / __FINALLY constructs instead of the Windows RPC API, which
is unimplemented, and appears to be fairly tricky or impossible to do
portably.  However, the current constructs aren't powerful enough to be a
substitution at the moment, so this patch extends them by allowing the
exception filter and finally function to take a void pointer as an argument.

---
 dlls/ntdll/exception.c   |   18 ++++++++++++---
 include/wine/exception.h |   54 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
index c039dd4..5c9876e 100644
--- a/dlls/ntdll/exception.c
+++ b/dlls/ntdll/exception.c
@@ -577,17 +577,24 @@ DWORD __wine_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION
     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
         return ExceptionContinueSearch;
 
-    if (wine_frame->u.filter == (void *)1)  /* special hack for page faults */
+    if (wine_frame->type == 1
+        /* special hack for page faults */
+        && wine_frame->u.filter == (void *)1)
     {
         if (record->ExceptionCode != STATUS_ACCESS_VIOLATION)
             return ExceptionContinueSearch;
     }
-    else if (wine_frame->u.filter)
+    else if ((wine_frame->type == 1 && wine_frame->u.filter)
+             || (wine_frame->type == 2 && wine_frame->u.filter2))
     {
         EXCEPTION_POINTERS ptrs;
+        LONG code;
         ptrs.ExceptionRecord = record;
         ptrs.ContextRecord = context;
-        switch(wine_frame->u.filter( &ptrs ))
+        code = (wine_frame->type == 1
+                ? wine_frame->u.filter( &ptrs )
+                : wine_frame->u.filter2( &ptrs, wine_frame->param ));
+        switch(code)
         {
         case EXCEPTION_CONTINUE_SEARCH:
             return ExceptionContinueSearch;
@@ -621,7 +628,10 @@ DWORD __wine_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_R
     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
     {
         __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
-        wine_frame->u.finally_func( FALSE );
+        if (wine_frame->type == 1)
+            wine_frame->u.finally_func( FALSE );
+        else
+            wine_frame->u.finally_func2( FALSE, wine_frame->param );
     }
     return ExceptionContinueSearch;
 }
diff --git a/include/wine/exception.h b/include/wine/exception.h
index eebfdfb..90aab11 100644
--- a/include/wine/exception.h
+++ b/include/wine/exception.h
@@ -32,7 +32,7 @@
  * {
  *     do some stuff that can raise an exception
  * }
- * __EXCEPT(filter_func,param)
+ * __EXCEPT(filter_func)
  * {
  *     handle the exception here
  * }
@@ -44,7 +44,7 @@
  * {
  *     do some stuff that can raise an exception
  * }
- * __FINALLY(finally_func,param)
+ * __FINALLY(finally_func)
  *
  * The filter_func must be defined with the WINE_EXCEPTION_FILTER
  * macro, and return one of the EXCEPTION_* code; it can use
@@ -53,6 +53,16 @@
  *
  * The finally_func must be defined with the WINE_FINALLY_FUNC macro.
  *
+ * __EXCEPT and __FINALLY may be replaced with __EXCEPT2 and __FINALLY2
+ * respectively.  These take a second argument which is the parameter of
+ * the function.  The parameter must be of type pointer to void.  Declare
+ * these functions with WINE_EXCEPTION_FILTER2 and WINE_FINALLY_FUNC2.
+ *
+ * Note that both the function and parameter argument may be evaluated before
+ * any of the __TRY/__EXCEPT/__FINALLY blocks execute, and they may be expanded
+ * more than once.  All of this is unspecified, so it is a good idea to only
+ * use simple pointers that have been previously initialized.
+ *
  * Warning: inside a __TRY or __EXCEPT block, 'break' or 'continue' statements
  *          break out of the current block. You cannot use 'return', 'goto'
  *          or 'longjmp' to leave a __TRY block, as this will surely crash.
@@ -69,7 +79,9 @@
 
 #define __TRY __try
 #define __EXCEPT(func) __except((func)(GetExceptionInformation()))
+#define __EXCEPT2(func, param) __except((func)(GetExceptionInformation(), (param)))
 #define __FINALLY(func) __finally { (func)(!AbnormalTermination()); }
+#define __FINALLY2(func, param) __finally { (func)(!AbnormalTermination(), (param)); }
 #define __ENDTRY /*nothing*/
 #define __EXCEPT_PAGE_FAULT __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
 
@@ -93,6 +105,21 @@
          } else { \
              __f.frame.Handler = __wine_exception_handler; \
              __f.u.filter = (func); \
+             __f.type = 1; \
+             __wine_push_frame( &__f.frame ); \
+             if (sigsetjmp( __f.jmp, 1 )) { \
+                 const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
+                 do {
+
+#define __EXCEPT2(func, p) \
+             } while(0); \
+             __wine_pop_frame( &__f.frame ); \
+             break; \
+         } else { \
+             __f.frame.Handler = __wine_exception_handler; \
+             __f.u.filter2 = (func); \
+             __f.param = (p); \
+             __f.type = 2; \
              __wine_push_frame( &__f.frame ); \
              if (sigsetjmp( __f.jmp, 1 )) { \
                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
@@ -114,20 +141,39 @@
          } else { \
              __f.frame.Handler = __wine_finally_handler; \
              __f.u.finally_func = (func); \
+             __f.type = 1; \
              __wine_push_frame( &__f.frame ); \
              __first = 0; \
          } \
     } while (0);
 
+#define __FINALLY2(func, p) \
+             } while(0); \
+             __wine_pop_frame( &__f.frame ); \
+             (func)(1, (p)); \
+             break; \
+         } else { \
+             __f.frame.Handler = __wine_finally_handler; \
+             __f.u.finally_func2 = (func); \
+             __f.param = (p); \
+             __f.type = 2; \
+             __wine_push_frame( &__f.frame ); \
+             __first = 0; \
+         } \
+    } while (0);
 
 typedef LONG (CALLBACK *__WINE_FILTER)(PEXCEPTION_POINTERS);
 typedef void (CALLBACK *__WINE_FINALLY)(BOOL);
+typedef LONG (CALLBACK *__WINE_FILTER2)(PEXCEPTION_POINTERS, void *);
+typedef void (CALLBACK *__WINE_FINALLY2)(BOOL, void *);
 
 /* convenience handler for page fault exceptions */
 #define __EXCEPT_PAGE_FAULT __EXCEPT( (__WINE_FILTER)1 )
 
 #define WINE_EXCEPTION_FILTER(func) LONG WINAPI func( EXCEPTION_POINTERS *__eptr )
 #define WINE_FINALLY_FUNC(func) void WINAPI func( BOOL __normal )
+#define WINE_EXCEPTION_FILTER2(func, param) LONG WINAPI func( EXCEPTION_POINTERS *__eptr, void *param )
+#define WINE_FINALLY_FUNC2(func, param) void WINAPI func( BOOL __normal, void *param )
 
 #define GetExceptionInformation() (__eptr)
 #define GetExceptionCode()        (__eptr->ExceptionRecord->ExceptionCode)
@@ -136,13 +182,17 @@ typedef void (CALLBACK *__WINE_FINALLY)(BOOL);
 typedef struct __tagWINE_FRAME
 {
     EXCEPTION_REGISTRATION_RECORD frame;
+    int type;
     union
     {
         /* exception data */
         __WINE_FILTER filter;
+        __WINE_FILTER2 filter2;
         /* finally data */
         __WINE_FINALLY finally_func;
+        __WINE_FINALLY2 finally_func2;
     } u;
+    void *param;
     sigjmp_buf jmp;
     /* hack to make GetExceptionCode() work in handler */
     DWORD ExceptionCode;



More information about the wine-patches mailing list