Let me know what you think of these. So far, I like them better
than the original versions, although in solving some limitations of the old
macros, I've created some new ones.
This version avoids ({ }) entirely, in favor of Ove's original thought,
which was to use __LINE__; therefore, putting multiple __(finally|except)
clauses in the same line probably breaks.
Otherwise, these are better macros. They are slightly more easily
understood (although still pretty darn confusing, especially in
the debugger), probably more resiliant against compiler optimizations,
and have much less awful performance. Best of all, they ought to
properly re-raise exceptions after executing finally clauses.
There is some cruft in there, btw, which will be fixed before I
submit anything to patches.
They still break break/continue, of course, since they still rely on
__TRY / __EXCEPT blocks to do the dirty-work.
You can run the original seh_macros.c test against these successfully,
except for the "absurdly nested" ones which use macros and presumably
would fail quite dramatically due to __LINE__ duplications.
FWIW, compared to the degree of "pressing need" for these macros,
I have already spent way too much time on them... But the old ones
kind of sucked, and, frankly, it's a fun semantic puzzle that requires
pusing the limits of good old cpp just a _bit_ further than may have been
intended ... so, here it is.
Note that I'm declaring a variable in the header file here. I guess,
I should fix this by creating an internal API in ntdll? I never quite
figured out whether global non-static variables in a dll are thread-local,
or what... (same for lexically scoped static ones -- real clueless here, and
building a new system so I don't have much doco's at my fingertips ATM)
Sooo.... Anyone want to help me decide what's the best way to get a thread-local
global variable instantiated? Probably, my previous attempt with TlsAlloc was
semantically correct, but that was /way/ too fat a solution, I'd like something
much quicker if its at all possible.
Otherwise this won't be threadsafe, which seems like a bad call, esp. since
such code will probably end up being used to guard against unacceptable resource
leakage..
warning, cut-and-pasted this patch in chunks so it might be bugged... should
be clear enough how to duplicate, however, if it fails...
--- ../wine.vanilla/include/wine/exception.h 2003-01-29 21:50:14.000000000 -0600
+++ ./include/wine/exception.h 2003-02-09 01:33:45.000000000 -0600
@@ -21,8 +21,12 @@
#ifndef __WINE_WINE_EXCEPTION_H
#define __WINE_WINE_EXCEPTION_H
+/* WRC can't find setjmp.h. Does it not check /usr/include? */
+#if (!(defined(__WRC__)))
+
#include <setjmp.h>
#include "windef.h"
+#include "excpt.h"
/* The following definitions allow using exceptions in Wine and Winelib code
*
@@ -59,6 +63,16 @@
* You can use them to leave a __EXCEPT block though.
*
* -- AJ
+ *
+ * Now we can implement the __try/__except/__finally magic of VC++ as standard (?) macros.
+ * this is a "good enough" implementation, it's incomplete, but should suffice for most uses.
+ *
+ * The macros require some symbols to be found in ntdll.dll.so, so link with that DLL if you
+ * use them.
+ *
+ * If you are using VC++ and this header, #define USE_COMPILER_EXCEPTIONS before you include it.
+ *
+ * -gmt
*/
/* Define this if you want to use your compiler built-in __try/__except support.
@@ -146,8 +160,90 @@
extern DWORD __wine_finally_handler( PEXCEPTION_RECORD record, EXCEPTION_FRAME *frame,
CONTEXT *context, LPVOID pdispatcher );
+
+#if (!defined(NO_VC_SEH_MACROS))
+
+#ifndef _WINE_ALREADY_DEFINED_SEH_MACROS__
+#define _WINE_ALREADY_DEFINED_SEH_MACROS__
+
+/* fixme: should be renamed since these are used for except too */
+typedef void (*__p_seh_finally_executer) ();
+typedef void (*__p_seh_dotry_executer) (__p_seh_finally_executer);
+__p_seh_finally_executer __thread_outermost_handler_ptr;
+
+#define __SEH_LINEUNIQ_CAT2(x,y) __SEH_LINEUNIQ_ ## y ## x
+#define __SEH_LINEUNIQ_CAT1(x,y) __SEH_LINEUNIQ_CAT2(x,y)
+
+#define __SEH_LINEUNIQ_NULLMACRO(x) x
+#define __SEH_LINEUNIQ_MAGIC_LINE __SEH_LINEUNIQ_NULLMACRO( __LINE__ )
+
+#define __SEH_LINEUNIQ_ID(x) __SEH_LINEUNIQ_CAT1( __SEH_LINEUNIQ_MAGIC_LINE , x )
+
+#define __try \
+ do { \
+ void dotry(__p_seh_finally_executer fin) { \
+ __label__ __seh_macro_exit_spot; \
+ auto WINE_EXCEPTION_FILTER(__wine_seh_macro_exception_handler); \
+ __TRY { \
+ { \
+
+#define __finally \
+ } \
+ __seh_macro_exit_spot: \
+ if (0) goto __seh_macro_exit_spot; \
+ } __EXCEPT( __wine_seh_macro_exception_handler ) { \
+ } __ENDTRY \
+ (*fin)(); \
+ WINE_EXCEPTION_FILTER(__wine_seh_macro_exception_handler) { \
+ (*fin)(); \
+ return EXCEPTION_CONTINUE_SEARCH; \
+ } \
+ } \
+ goto __SEH_LINEUNIQ_ID(DETOUR); \
+ __SEH_LINEUNIQ_ID(RETOUR): \
+ dotry( __thread_outermost_handler_ptr ); \
+ } while (0); \
+ goto __SEH_LINEUNIQ_ID(AFTERFINALLY); \
+ auto void __SEH_LINEUNIQ_ID(Finally_Executer) (); \
+ __SEH_LINEUNIQ_ID(DETOUR): \
+ __thread_outermost_handler_ptr = & __SEH_LINEUNIQ_ID(Finally_Executer); \
+ goto __SEH_LINEUNIQ_ID(RETOUR); \
+ __SEH_LINEUNIQ_ID(AFTERFINALLY): ; \
+ void __SEH_LINEUNIQ_ID(Finally_Executer) ()
+
+#define __except(...) \
+ } \
+ __seh_macro_exit_spot: \
+ if (0) goto __seh_macro_exit_spot; \
+ } __EXCEPT( __wine_seh_macro_exception_handler ) { \
+ (*fin)(); \
+ } __ENDTRY \
+ WINE_EXCEPTION_FILTER(__wine_seh_macro_exception_handler) { \
+ return ( __VA_ARGS__ ); \
+ } \
+ } \
+ goto __SEH_LINEUNIQ_ID(DETOUR); \
+ __SEH_LINEUNIQ_ID(RETOUR): \
+ dotry( __thread_outermost_handler_ptr ); \
+ } while (0); \
+ goto __SEH_LINEUNIQ_ID(AFTEREXCEPT); \
+ auto void __SEH_LINEUNIQ_ID(Except_Executer) (); \
+ __SEH_LINEUNIQ_ID(DETOUR): \
+ __thread_outermost_handler_ptr = & __SEH_LINEUNIQ_ID(Except_Executer); \
+ goto __SEH_LINEUNIQ_ID(RETOUR); \
+ __SEH_LINEUNIQ_ID(AFTEREXCEPT): ; \
+ void __SEH_LINEUNIQ_ID(Except_Executer) ()
+
+#define __leave goto __seh_macro_exit_spot
+
+#endif /* _WINE_ALREADY_DEFINED_SEH_MACROS__ */
+
+#endif /* NO_VC_SEH_MACROS */
+
#endif /* USE_COMPILER_EXCEPTIONS */
+#endif /* __WRC__ */
+
static inline EXCEPTION_FRAME * WINE_UNUSED __wine_push_frame( EXCEPTION_FRAME *frame )
{
#if defined(__GNUC__) && defined(__i386__)
--
gmt