widl [2/9]: Add an option to use Wine exception handlers.

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


(Sorry, forgot [1/9] on the previous patch.  It's part of this set.)

This patch adds a --wine-seh option to widl to use Wine's SEH instead of
the Windows one.  This patch is actually incomplete since it's a bit of a
pain to only have a function execute "finally", instead of a block of code
that has the advantage of being in the same scope as local variables.
Hence, this patch cheats a little in one area where it should do something
in a finally block, it just does it on normal execution (if no exception is
raises).  This isn't really any worse than what currently happens, because
currently if there's an exception we crash.  I'd say it's still an
improvement, but I'll finish it up shortly once some more important things
are out of the way.

---
 tools/widl/client.c    |   40 +++++++++++++-------
 tools/widl/proxy.c     |   96 ++++++++++++++++++++++++++++++++++++++----------
 tools/widl/server.c    |   58 +++++++++++++++++++++++------
 tools/widl/widl.c      |    9 ++++-
 tools/widl/widl.h      |    1 +
 tools/widl/widl.man.in |    4 ++
 6 files changed, 161 insertions(+), 47 deletions(-)

diff --git a/tools/widl/client.c b/tools/widl/client.c
index 696dd83..f502fd6 100644
--- a/tools/widl/client.c
+++ b/tools/widl/client.c
@@ -144,7 +144,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
         /* check pointers */
         check_pointers(func);
 
-        print_client("RpcTryFinally\n");
+        print_client("%s\n", wine_seh ? "__TRY" : "RpcTryFinally");
         print_client("{\n");
         indent++;
 
@@ -231,19 +231,18 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
 
         indent--;
         print_client("}\n");
-        print_client("RpcFinally\n");
-        print_client("{\n");
-        indent++;
-
-
-        /* FIXME: emit client finally code */
-
-        print_client("NdrFreeBuffer((PMIDL_STUB_MESSAGE)&_StubMsg);\n");
-
-        indent--;
-        print_client("}\n");
-        print_client("RpcEndFinally\n");
-
+        if (wine_seh)
+            print_client("__FINALLY2(WIDL_finally_free_buffer, &_StubMsg)\n");
+        else
+        {
+            print_client("RpcFinally\n");
+            print_client("{\n");
+            indent++;
+            print_client("NdrFreeBuffer((PMIDL_STUB_MESSAGE)&_StubMsg);\n");
+            indent--;
+            print_client("}\n");
+            print_client("RpcEndFinally\n");
+        }
 
         /* emit return code */
         if (!is_void(def->type))
@@ -379,6 +378,8 @@ static void init_client(void)
     print_client("#endif\n");
     fprintf(client, "\n");
     print_client("#include \"%s\"\n", header_name);
+    if (wine_seh)
+        print_client("#include \"wine/exception.h\"\n");
     fprintf(client, "\n");
 }
 
@@ -404,6 +405,17 @@ void write_client(ifref_list_t *ifaces)
         write_expr_eval_routine_list(client, client_token);
     write_user_quad_list(client);
 
+    if (wine_seh)
+    {
+        print_client("static WINE_FINALLY_FUNC2(WIDL_finally_free_buffer, p)\n");
+        print_client("{\n");
+        ++indent;
+        print_client("PMIDL_STUB_MESSAGE sm = (PMIDL_STUB_MESSAGE) p;\n");
+        print_client("NdrFreeBuffer(sm);\n");
+        --indent;
+        print_client("}\n");
+    }
+
     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, ifref_t, entry )
     {
         if (!need_stub(iface->iface))
diff --git a/tools/widl/proxy.c b/tools/widl/proxy.c
index 8a81885..ac008b7 100644
--- a/tools/widl/proxy.c
+++ b/tools/widl/proxy.c
@@ -109,9 +109,47 @@ static void init_proxy(ifref_list_t *ifaces)
   print_proxy( "#endif /* __RPCPROXY_H_VERSION__ */\n");
   print_proxy( "\n");
   print_proxy( "#include \"%s\"\n", header_name);
+  if (wine_seh)
+      print_proxy( "#include \"wine/exception.h\"\n");
   print_proxy( "\n");
   write_formatstringsdecl(proxy, indent, ifaces, need_proxy);
   write_stubdescproto();
+
+  if (wine_seh) {
+      print_proxy( "typedef struct\n" );
+      print_proxy( "{\n" );
+      ++indent;
+      print_proxy( "void *This;\n" );
+      print_proxy( "PMIDL_STUB_MESSAGE sm;\n" );
+      --indent;
+      print_proxy( "} WIDL_finally_info_t;\n\n" );
+
+      print_proxy( "static WINE_FINALLY_FUNC2(WIDL_finally_free_buffer, p)\n" );
+      print_proxy( "{\n" );
+      ++indent;
+      print_proxy( "WIDL_finally_info_t *i = (WIDL_finally_info_t *) p;\n" );
+      print_proxy( "NdrProxyFreeBuffer(i->This, i->sm);\n" );
+      --indent;
+      print_proxy( "}\n\n" );
+
+      print_proxy( "static WINE_EXCEPTION_FILTER2(WIDL_except_filter, p)\n" );
+      print_proxy( "{\n" );
+      ++indent;
+      print_proxy( "PMIDL_STUB_MESSAGE sm = (PMIDL_STUB_MESSAGE) p;\n" );
+      print_proxy( "return sm->dwStubPhase != PROXY_SENDRECEIVE\n" );
+      print_proxy( "       ? EXCEPTION_EXECUTE_HANDLER\n" );
+      print_proxy( "       : EXCEPTION_CONTINUE_SEARCH;\n" );
+      --indent;
+      print_proxy( "}\n\n" );
+
+      print_proxy( "static WINE_FINALLY_FUNC2(WIDL_finally_free_args, p)\n" );
+      print_proxy( "{\n" );
+      ++indent;
+      print_proxy( "/* FIXME: We really need one of these for each stub,\n" );
+      print_proxy( "   and it should call NdrFooFree on all the args,  */\n" );
+      --indent;
+      print_proxy( "}\n\n" );
+  }
 }
 
 static void clear_output_vars( const var_list_t *args )
@@ -268,18 +306,20 @@ static void gen_proxy(type_t *iface, const func_t *cur, int idx,
   }
   print_proxy( "RPC_MESSAGE _RpcMessage;\n" );
   print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" );
+  if (wine_seh)
+    print_proxy( "WIDL_finally_info_t WIDL_fi = { This, &_StubMsg };\n" );
   print_proxy( "\n");
 
   /* FIXME: trace */
   clear_output_vars( cur->args );
 
-  print_proxy( "RpcTryExcept\n" );
+  print_proxy( "%s\n", wine_seh ? "__TRY" : "RpcTryExcept" );
   print_proxy( "{\n" );
   indent++;
   print_proxy( "NdrProxyInitialize(This, &_RpcMessage, &_StubMsg, &Object_StubDesc, %d);\n", idx);
   proxy_check_pointers( cur->args );
 
-  print_proxy( "RpcTryFinally\n" );
+  print_proxy( "%s\n", wine_seh ? "__TRY" : "RpcTryFinally" );
   print_proxy( "{\n" );
   indent++;
 
@@ -307,25 +347,33 @@ static void gen_proxy(type_t *iface, const func_t *cur, int idx,
 
   indent--;
   print_proxy( "}\n");
-  print_proxy( "RpcFinally\n" );
-  print_proxy( "{\n" );
-  indent++;
-  print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" );
-  indent--;
-  print_proxy( "}\n");
-  print_proxy( "RpcEndFinally\n" );
+  if (wine_seh)
+    print_proxy( "__FINALLY2(WIDL_finally_free_buffer, &WIDL_fi)\n" );
+  else {
+    print_proxy( "RpcFinally\n" );
+    print_proxy( "{\n" );
+    indent++;
+    print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" );
+    indent--;
+    print_proxy( "}\n");
+    print_proxy( "RpcEndFinally\n" );
+  }
   indent--;
   print_proxy( "}\n" );
-  print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
+  if (wine_seh)
+    print_proxy( "__EXCEPT2(WIDL_except_filter, &_StubMsg)\n" );
+  else
+    print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
   print_proxy( "{\n" );
   if (has_ret) {
     indent++;
     proxy_free_variables( cur->args );
-    print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
+    print_proxy( "_RetVal = NdrProxyErrorHandler(%sExceptionCode());\n",
+                 wine_seh ? "Get" : "Rpc" );
     indent--;
   }
   print_proxy( "}\n" );
-  print_proxy( "RpcEndExcept\n" );
+  print_proxy( "%s\n", wine_seh ? "__ENDTRY" :"RpcEndExcept" );
 
   if (has_ret) {
     print_proxy( "return _RetVal;\n" );
@@ -366,7 +414,7 @@ static void gen_stub(type_t *iface, const func_t *cur, const char *cas,
 
   write_parameters_init(proxy, indent, cur);
 
-  print_proxy("RpcTryFinally\n");
+  print_proxy("%s\n", wine_seh ? "__TRY" : "RpcTryFinally");
   print_proxy("{\n");
   indent++;
   print_proxy("if ((_pRpcMessage->DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
@@ -419,13 +467,21 @@ static void gen_stub(type_t *iface, const func_t *cur, const char *cas,
 
   indent--;
   print_proxy("}\n");
-  print_proxy("RpcFinally\n");
-  print_proxy("{\n");
-
-  write_remoting_arguments(proxy, indent+1, cur, PASS_OUT, PHASE_FREE);
-
-  print_proxy("}\n");
-  print_proxy("RpcEndFinally\n");
+  if (wine_seh)
+  {
+      print_proxy("__FINALLY2(WIDL_finally_free_args, NULL)\n\n");
+      print_proxy("{\t/* FIXME: Should do this in the __FINALLY function.  */\n");
+      write_remoting_arguments(proxy, indent+1, cur, PASS_OUT, PHASE_FREE);
+      print_proxy("}\n");
+  }
+  else
+  {
+      print_proxy("RpcFinally\n");
+      print_proxy("{\n");
+      write_remoting_arguments(proxy, indent+1, cur, PASS_OUT, PHASE_FREE);
+      print_proxy("}\n");
+      print_proxy("RpcEndFinally\n");
+  }
 
   print_proxy("_pRpcMessage->BufferLength = _StubMsg.Buffer - (unsigned char *)_pRpcMessage->Buffer;\n");
   indent--;
diff --git a/tools/widl/server.c b/tools/widl/server.c
index a52c729..9b30ade 100644
--- a/tools/widl/server.c
+++ b/tools/widl/server.c
@@ -123,10 +123,10 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
             fprintf(server, "\n");
         }
 
-        print_server("RpcTryFinally\n");
+        print_server("%s\n", wine_seh ? "__TRY" : "RpcTryFinally");
         print_server("{\n");
         indent++;
-        print_server("RpcTryExcept\n");
+        print_server("%s\n", wine_seh ? "__TRY" : "RpcTryExcept");
         print_server("{\n");
         indent++;
 
@@ -153,13 +153,16 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
         print_server("}\n");
         indent--;
         print_server("}\n");
-        print_server("RpcExcept(RPC_BAD_STUB_DATA_EXCEPTION_FILTER)\n");
+        if (wine_seh)
+            print_server("__EXCEPT2(WIDL_except_filter, NULL)\n");
+        else
+            print_server("RpcExcept(RPC_BAD_STUB_DATA_EXCEPTION_FILTER)\n");
         print_server("{\n");
         indent++;
         print_server("RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
         indent--;
         print_server("}\n");
-        print_server("RpcEndExcept\n");
+        print_server("%s\n", wine_seh ? "__ENDTRY" : "RpcEndExcept");
         fprintf(server, "\n");
 
         /* Assign 'out' arguments */
@@ -231,15 +234,22 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
 
         indent--;
         print_server("}\n");
-        print_server("RpcFinally\n");
-        print_server("{\n");
-        indent++;
-
-        write_remoting_arguments(server, indent, func, PASS_OUT, PHASE_FREE);
 
-        indent--;
-        print_server("}\n");
-        print_server("RpcEndFinally\n");
+        if (wine_seh)
+        {
+            print_server("__FINALLY2(WIDL_finally_free_args, NULL)\n\n");
+            print_server("{\t/* FIXME: Should do this in the __FINALLY function.  */\n");
+            write_remoting_arguments(server, indent + 1, func, PASS_OUT, PHASE_FREE);
+            print_server("}\n");
+        }
+        else
+        {
+            print_server("RpcFinally\n");
+            print_server("{\n");
+            write_remoting_arguments(server, indent + 1, func, PASS_OUT, PHASE_FREE);
+            print_server("}\n");
+            print_server("RpcEndFinally\n");
+        }
 
         /* calculate buffer length */
         fprintf(server, "\n");
@@ -392,7 +402,31 @@ static void init_server(void)
     print_server("#include <string.h>\n");
     fprintf(server, "\n");
     print_server("#include \"%s\"\n", header_name);
+    if (wine_seh)
+        print_server("#include \"wine/exception.h\"\n");
     fprintf(server, "\n");
+
+    if (wine_seh)
+    {
+        print_server("static WINE_EXCEPTION_FILTER2(WIDL_except_filter, p)\n");
+        print_server("{\n");
+        ++indent;
+        print_server("return (GetExceptionCode() == STATUS_ACCESS_VIOLATION\n");
+        print_server("        || GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT\n");
+        print_server("        || GetExceptionCode() == RPC_X_BAD_STUB_DATA)\n");
+        print_server("       ? EXCEPTION_EXECUTE_HANDLER\n");
+        print_server("       : EXCEPTION_CONTINUE_SEARCH;\n");
+        --indent;
+        print_server("}\n\n");
+
+        print_server("static WINE_FINALLY_FUNC2(WIDL_finally_free_args, p)\n");
+        print_server("{\n");
+        ++indent;
+        print_server("/* FIXME: We really need one of these for each stub,\n");
+        print_server("   and it should call NdrFooFree on all the args,  */\n");
+        --indent;
+        print_server( "}\n\n");
+    }
 }
 
 
diff --git a/tools/widl/widl.c b/tools/widl/widl.c
index 0dcc069..ef4d156 100644
--- a/tools/widl/widl.c
+++ b/tools/widl/widl.c
@@ -78,6 +78,7 @@ static const char usage[] =
 "   -U file     Name of interface identifiers file (default is infile_i.c)\n"
 "   -V          Print version and exit\n"
 "   -W          Enable pedantic warnings\n"
+"   --wine-seh  Use Wine structured exception handling instead of the RPC API\n"
 "Debug level 'n' is a bitmask with following meaning:\n"
 "    * 0x01 Tell which resource is parsed (verbose mode)\n"
 "    * 0x02 Dump internal structures\n"
@@ -106,6 +107,7 @@ int do_idfile = 0;
 int do_dlldata = 0;
 int no_preprocess = 0;
 int old_names = 0;
+int wine_seh = 0;
 
 char *input_name;
 char *header_name;
@@ -141,7 +143,8 @@ enum {
     LOCAL_STUBS_OPTION,
     PREFIX_ALL_OPTION,
     PREFIX_CLIENT_OPTION,
-    PREFIX_SERVER_OPTION
+    PREFIX_SERVER_OPTION,
+    WINE_SEH_OPTION
 };
 
 static const char short_options[] =
@@ -154,6 +157,7 @@ static const struct option long_options[] = {
     { "prefix-all", required_argument, 0, PREFIX_ALL_OPTION },
     { "prefix-client", required_argument, 0, PREFIX_CLIENT_OPTION },
     { "prefix-server", required_argument, 0, PREFIX_SERVER_OPTION },
+    { "wine-seh", no_argument, 0, WINE_SEH_OPTION },
     { 0, 0, 0, 0 }
 };
 
@@ -372,6 +376,9 @@ int main(int argc,char *argv[])
     case PREFIX_SERVER_OPTION:
       prefix_server = xstrdup(optarg);
       break;
+    case WINE_SEH_OPTION:
+      wine_seh = 1;
+      break;
     case 'c':
       do_everything = 0;
       do_client = 1;
diff --git a/tools/widl/widl.h b/tools/widl/widl.h
index 924b67a..381d7e2 100644
--- a/tools/widl/widl.h
+++ b/tools/widl/widl.h
@@ -45,6 +45,7 @@ extern int do_server;
 extern int do_idfile;
 extern int do_dlldata;
 extern int old_names;
+extern int wine_seh;
 
 extern char *input_name;
 extern char *header_name;
diff --git a/tools/widl/widl.man.in b/tools/widl/widl.man.in
index df7d1c0..3557b62 100644
--- a/tools/widl/widl.man.in
+++ b/tools/widl/widl.man.in
@@ -102,6 +102,10 @@ number.  For the meaning of values, see the \fBDebug\fR section.
 .IP "\fB--local-stubs=\fIfile\fR"
 Generate empty stubs for call_as/local methods in an object interface and
 write them to \fIfile\fR.
+.IP "\fB--wine-seh\fR"
+Generate Wine's structured exception handling contructs
+(__TRY / __EXCEPT2 / __FINALLY2) instead of the Windows RPC exception
+handling constructs which are based on non-portable compiler extensions.
 .PP
 .SH Debug
 Debug level \fIn\fR is a bitmask with the following meaning:



More information about the wine-patches mailing list