widl: Add support for exception handling in the generated proxy code.
[wine] / tools / widl / proxy.c
1 /*
2  * IDL Compiler
3  *
4  * Copyright 2002 Ove Kaaven
5  * Copyright 2004 Mike McCormack
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "widl.h"
34 #include "utils.h"
35 #include "parser.h"
36 #include "header.h"
37 #include "typegen.h"
38 #include "expr.h"
39
40 #define END_OF_LIST(list)       \
41   do {                          \
42     if (list) {                 \
43       while (NEXT_LINK(list))   \
44         list = NEXT_LINK(list); \
45     }                           \
46   } while(0)
47
48 static FILE* proxy;
49 static int indent = 0;
50
51 /* FIXME: support generation of stubless proxies */
52
53 static void print_proxy( const char *format, ... )
54 {
55   va_list va;
56   va_start( va, format );
57   print( proxy, indent, format, va );
58   va_end( va );
59 }
60
61 static void write_stubdescproto(void)
62 {
63   print_proxy( "static const MIDL_STUB_DESC Object_StubDesc;\n");
64   print_proxy( "\n");
65 }
66
67 static void write_stubdesc(int expr_eval_routines)
68 {
69   print_proxy( "static const MIDL_STUB_DESC Object_StubDesc =\n{\n");
70   indent++;
71   print_proxy( "0,\n");
72   print_proxy( "NdrOleAllocate,\n");
73   print_proxy( "NdrOleFree,\n");
74   print_proxy( "{0}, 0, 0, %s, 0,\n", expr_eval_routines ? "ExprEvalRoutines" : "0");
75   print_proxy( "__MIDL_TypeFormatString.Format,\n");
76   print_proxy( "1, /* -error bounds_check flag */\n");
77   print_proxy( "0x10001, /* Ndr library version */\n");
78   print_proxy( "0,\n");
79   print_proxy( "0x50100a4, /* MIDL Version 5.1.164 */\n");
80   print_proxy( "0,\n");
81   print_proxy("%s,\n", list_empty(&user_type_list) ? "0" : "UserMarshalRoutines");
82   print_proxy( "0,  /* notify & notify_flag routine table */\n");
83   print_proxy( "1,  /* Flags */\n");
84   print_proxy( "0,  /* Reserved3 */\n");
85   print_proxy( "0,  /* Reserved4 */\n");
86   print_proxy( "0   /* Reserved5 */\n");
87   indent--;
88   print_proxy( "};\n");
89   print_proxy( "\n");
90 }
91
92 static void init_proxy(const statement_list_t *stmts)
93 {
94   if (proxy) return;
95   if(!(proxy = fopen(proxy_name, "w")))
96     error("Could not open %s for output\n", proxy_name);
97   print_proxy( "/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", PACKAGE_VERSION, input_name);
98   print_proxy( "\n");
99   print_proxy( "#ifndef __REDQ_RPCPROXY_H_VERSION__\n");
100   print_proxy( "#define __REQUIRED_RPCPROXY_H_VERSION__ 440\n");
101   print_proxy( "#endif /* __REDQ_RPCPROXY_H_VERSION__ */\n");
102   print_proxy( "\n");
103   print_proxy( "#define __midl_proxy\n");
104   print_proxy( "#include \"objbase.h\"\n");
105   print_proxy( "#include \"rpcproxy.h\"\n");
106   print_proxy( "#ifndef __RPCPROXY_H_VERSION__\n");
107   print_proxy( "#error This code needs a newer version of rpcproxy.h\n");
108   print_proxy( "#endif /* __RPCPROXY_H_VERSION__ */\n");
109   print_proxy( "\n");
110   print_proxy( "#include \"%s\"\n", header_name);
111   print_proxy( "\n");
112   print_proxy( "#ifndef USE_COMPILER_EXCEPTIONS\n");
113   print_proxy( "\n");
114   print_proxy( "#include \"wine/exception.h\"\n");
115   print_proxy( "#undef RpcTryExcept\n");
116   print_proxy( "#undef RpcExcept\n");
117   print_proxy( "#undef RpcEndExcept\n");
118   print_proxy( "#undef RpcExceptionCode\n");
119   print_proxy( "\n");
120   print_proxy( "struct __proxy_frame\n");
121   print_proxy( "{\n");
122   print_proxy( "    EXCEPTION_REGISTRATION_RECORD frame;\n");
123   print_proxy( "    sigjmp_buf                    jmp;\n");
124   print_proxy( "    DWORD                         code;\n");
125   print_proxy( "    MIDL_STUB_MESSAGE            *stub;\n");
126   print_proxy( "};\n");
127   print_proxy( "\n");
128   print_proxy( "static DWORD __proxy_exception_handler( EXCEPTION_RECORD *record,\n");
129   print_proxy( "                                        EXCEPTION_REGISTRATION_RECORD *frame,\n");
130   print_proxy( "                                        CONTEXT *context,\n");
131   print_proxy( "                                        EXCEPTION_REGISTRATION_RECORD **pdispatcher )\n");
132   print_proxy( "{\n");
133   print_proxy( "    struct __proxy_frame *proxy_frame = (struct __proxy_frame *)frame;\n");
134   print_proxy( "\n");
135   print_proxy( "    if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))\n");
136   print_proxy( "        return ExceptionContinueSearch;\n");
137   print_proxy( "    if (proxy_frame->stub->dwStubPhase == PROXY_SENDRECEIVE)\n");
138   print_proxy( "        return ExceptionContinueSearch;\n");
139   print_proxy( "\n");
140   print_proxy( "    proxy_frame->code = record->ExceptionCode;\n");
141   print_proxy( "    __wine_rtl_unwind( frame, record );\n");
142   print_proxy( "    __wine_pop_frame( frame );\n");
143   print_proxy( "    siglongjmp( proxy_frame->jmp, 1 );\n");
144   print_proxy( "}\n");
145   print_proxy( "\n");
146   print_proxy( "#define RpcTryExcept \\\n");
147   print_proxy( "    do { \\\n");
148   print_proxy( "        struct __proxy_frame __proxy_frame; \\\n");
149   print_proxy( "        __proxy_frame.frame.Handler = __proxy_exception_handler; \\\n");
150   print_proxy( "        __proxy_frame.stub = &_StubMsg; \\\n");
151   print_proxy( "        if (!sigsetjmp( __proxy_frame.jmp, 0 )) \\\n");
152   print_proxy( "        { \\\n");
153   print_proxy( "            __wine_push_frame( &__proxy_frame.frame ); \\\n");
154   print_proxy( "            {\n");
155   print_proxy( "\n");
156   print_proxy( "#define RpcExcept(expr) \\\n");
157   print_proxy( "            } \\\n");
158   print_proxy( "            __wine_pop_frame( &__proxy_frame.frame ); \\\n");
159   print_proxy( "        } \\\n");
160   print_proxy( "        else \\\n");
161   print_proxy( "        {\n");
162   print_proxy( "\n");
163   print_proxy( "#define RpcEndExcept \\\n");
164   print_proxy( "        } \\\n");
165   print_proxy( "    } while(0);\n");
166   print_proxy( "\n");
167   print_proxy( "#define RpcExceptionCode() (__proxy_frame.code)\n");
168   print_proxy( "\n");
169   print_proxy( "#endif /* USE_COMPILER_EXCEPTIONS */\n");
170   print_proxy( "\n");
171   write_formatstringsdecl(proxy, indent, stmts, need_proxy);
172   write_stubdescproto();
173 }
174
175 static void clear_output_vars( const var_list_t *args )
176 {
177   const var_t *arg;
178
179   if (!args) return;
180   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
181   {
182     if (is_attr(arg->attrs, ATTR_OUT) && !is_attr(arg->attrs, ATTR_IN)) {
183       print_proxy( "if(%s)\n", arg->name );
184       indent++;
185       print_proxy( "MIDL_memset( %s, 0, sizeof( *%s ));\n", arg->name, arg->name );
186       indent--;
187     }
188   }
189 }
190
191 int is_var_ptr(const var_t *v)
192 {
193   return is_ptr(v->type);
194 }
195
196 int cant_be_null(const var_t *v)
197 {
198   /* Search backwards for the most recent pointer attribute.  */
199   const attr_list_t *attrs = v->attrs;
200   const type_t *type = v->type;
201
202   if (! attrs && type)
203   {
204     attrs = type->attrs;
205     type = type->ref;
206   }
207
208   while (attrs)
209   {
210     int t = get_attrv(attrs, ATTR_POINTERTYPE);
211
212     if (t == RPC_FC_FP || t == RPC_FC_OP || t == RPC_FC_UP)
213       return 0;
214
215     if (t == RPC_FC_RP)
216       return 1;
217
218     if (type)
219     {
220       attrs = type->attrs;
221       type = type->ref;
222     }
223     else
224       attrs = NULL;
225   }
226
227   return 1;                             /* Default is RPC_FC_RP.  */
228 }
229
230 static void proxy_check_pointers( const var_list_t *args )
231 {
232   const var_t *arg;
233
234   if (!args) return;
235   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
236   {
237     if (is_var_ptr(arg) && cant_be_null(arg)) {
238         print_proxy( "if(!%s)\n", arg->name );
239         indent++;
240         print_proxy( "RpcRaiseException(RPC_X_NULL_REF_POINTER);\n");
241         indent--;
242     }
243   }
244 }
245
246 static void free_variable( const var_t *arg )
247 {
248   unsigned int type_offset = arg->type->typestring_offset;
249   expr_t *iid;
250   type_t *type = arg->type;
251   expr_t *size = get_size_is_expr(type, arg->name);
252
253   if (size)
254   {
255     print_proxy( "_StubMsg.MaxCount = " );
256     write_expr(proxy, size, 0, 1, NULL, NULL);
257     fprintf(proxy, ";\n\n");
258     print_proxy( "NdrClearOutParameters( &_StubMsg, ");
259     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%u], ", type_offset );
260     fprintf(proxy, "(void*)%s );\n", arg->name );
261     return;
262   }
263
264   switch( type->type )
265   {
266   case RPC_FC_BYTE:
267   case RPC_FC_CHAR:
268   case RPC_FC_WCHAR:
269   case RPC_FC_SHORT:
270   case RPC_FC_USHORT:
271   case RPC_FC_ENUM16:
272   case RPC_FC_LONG:
273   case RPC_FC_ULONG:
274   case RPC_FC_ENUM32:
275   case RPC_FC_STRUCT:
276     break;
277
278   case RPC_FC_FP:
279   case RPC_FC_IP:
280     iid = get_attrp( arg->attrs, ATTR_IIDIS );
281     if( iid )
282     {
283       print_proxy( "_StubMsg.MaxCount = (unsigned long) " );
284       write_expr(proxy, iid, 1, 1, NULL, NULL);
285       print_proxy( ";\n\n" );
286     }
287     print_proxy( "NdrClearOutParameters( &_StubMsg, ");
288     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%u], ", type_offset );
289     fprintf(proxy, "(void*)%s );\n", arg->name );
290     break;
291
292   default:
293     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
294   }
295 }
296
297 static void proxy_free_variables( var_list_t *args )
298 {
299   const var_t *arg;
300
301   if (!args) return;
302   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
303     if (is_attr(arg->attrs, ATTR_OUT))
304     {
305       free_variable( arg );
306       fprintf(proxy, "\n");
307     }
308 }
309
310 static void gen_proxy(type_t *iface, const func_t *cur, int idx,
311                       unsigned int proc_offset)
312 {
313   var_t *def = cur->def;
314   int has_ret = !is_void(get_func_return_type(cur));
315   int has_full_pointer = is_full_pointer_function(cur);
316   const char *callconv = get_attrp(def->type->attrs, ATTR_CALLCONV);
317   if (!callconv) callconv = "";
318
319   indent = 0;
320   write_type_decl_left(proxy, get_func_return_type(cur));
321   print_proxy( " %s %s_", callconv, iface->name);
322   write_name(proxy, def);
323   print_proxy( "_Proxy(\n");
324   write_args(proxy, cur->args, iface->name, 1, TRUE);
325   print_proxy( ")\n");
326   print_proxy( "{\n");
327   indent ++;
328   /* local variables */
329   if (has_ret) {
330     print_proxy( "" );
331     write_type_decl_left(proxy, get_func_return_type(cur));
332     print_proxy( " _RetVal;\n");
333   }
334   print_proxy( "RPC_MESSAGE _RpcMessage;\n" );
335   print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" );
336   if (has_ret) {
337     if (decl_indirect(get_func_return_type(cur)))
338       print_proxy("void *_p_%s = &%s;\n",
339                  "_RetVal", "_RetVal");
340   }
341   print_proxy( "\n");
342
343   if (has_full_pointer)
344     write_full_pointer_init(proxy, indent, cur, FALSE);
345
346   /* FIXME: trace */
347   clear_output_vars( cur->args );
348
349   print_proxy( "RpcTryExcept\n" );
350   print_proxy( "{\n" );
351   indent++;
352   print_proxy( "NdrProxyInitialize(This, &_RpcMessage, &_StubMsg, &Object_StubDesc, %d);\n", idx);
353   proxy_check_pointers( cur->args );
354
355   print_proxy( "RpcTryFinally\n" );
356   print_proxy( "{\n" );
357   indent++;
358
359   write_remoting_arguments(proxy, indent, cur, PASS_IN, PHASE_BUFFERSIZE);
360
361   print_proxy( "NdrProxyGetBuffer(This, &_StubMsg);\n" );
362
363   write_remoting_arguments(proxy, indent, cur, PASS_IN, PHASE_MARSHAL);
364
365   print_proxy( "NdrProxySendReceive(This, &_StubMsg);\n" );
366   fprintf(proxy, "\n");
367   print_proxy( "_StubMsg.BufferStart = _RpcMessage.Buffer;\n" );
368   print_proxy( "_StubMsg.BufferEnd   = _StubMsg.BufferStart + _RpcMessage.BufferLength;\n\n" );
369
370   print_proxy("if ((_RpcMessage.DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
371   indent++;
372   print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
373   indent--;
374   fprintf(proxy, "\n");
375
376   write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_UNMARSHAL);
377
378   if (has_ret)
379   {
380       if (decl_indirect(get_func_return_type(cur)))
381           print_proxy("MIDL_memset(&%s, 0, sizeof(%s));\n", "_RetVal", "_RetVal");
382       else if (is_ptr(get_func_return_type(cur)) || is_array(get_func_return_type(cur)))
383           print_proxy("%s = 0;\n", "_RetVal");
384       write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_UNMARSHAL);
385   }
386
387   indent--;
388   print_proxy( "}\n");
389   print_proxy( "RpcFinally\n" );
390   print_proxy( "{\n" );
391   indent++;
392   if (has_full_pointer)
393     write_full_pointer_free(proxy, indent, cur);
394   print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" );
395   indent--;
396   print_proxy( "}\n");
397   print_proxy( "RpcEndFinally\n" );
398   indent--;
399   print_proxy( "}\n" );
400   print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
401   print_proxy( "{\n" );
402   if (has_ret) {
403     indent++;
404     proxy_free_variables( cur->args );
405     print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
406     indent--;
407   }
408   print_proxy( "}\n" );
409   print_proxy( "RpcEndExcept\n" );
410
411   if (has_ret) {
412     print_proxy( "return _RetVal;\n" );
413   }
414   indent--;
415   print_proxy( "}\n");
416   print_proxy( "\n");
417 }
418
419 static void gen_stub(type_t *iface, const func_t *cur, const char *cas,
420                      unsigned int proc_offset)
421 {
422   var_t *def = cur->def;
423   const var_t *arg;
424   int has_ret = !is_void(get_func_return_type(cur));
425   int has_full_pointer = is_full_pointer_function(cur);
426
427   indent = 0;
428   print_proxy( "void __RPC_STUB %s_", iface->name);
429   write_name(proxy, def);
430   print_proxy( "_Stub(\n");
431   indent++;
432   print_proxy( "IRpcStubBuffer* This,\n");
433   print_proxy( "IRpcChannelBuffer *_pRpcChannelBuffer,\n");
434   print_proxy( "PRPC_MESSAGE _pRpcMessage,\n");
435   print_proxy( "DWORD* _pdwStubPhase)\n");
436   indent--;
437   print_proxy( "{\n");
438   indent++;
439   print_proxy("%s * _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name);
440   print_proxy("MIDL_STUB_MESSAGE _StubMsg;\n");
441   declare_stub_args( proxy, indent, cur );
442   fprintf(proxy, "\n");
443
444   /* FIXME: trace */
445
446   print_proxy("NdrStubInitialize(_pRpcMessage, &_StubMsg, &Object_StubDesc, _pRpcChannelBuffer);\n");
447   fprintf(proxy, "\n");
448
449   write_parameters_init(proxy, indent, cur);
450
451   print_proxy("RpcTryFinally\n");
452   print_proxy("{\n");
453   indent++;
454   if (has_full_pointer)
455     write_full_pointer_init(proxy, indent, cur, TRUE);
456   print_proxy("if ((_pRpcMessage->DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
457   indent++;
458   print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
459   indent--;
460   fprintf(proxy, "\n");
461
462   write_remoting_arguments(proxy, indent, cur, PASS_IN, PHASE_UNMARSHAL);
463   fprintf(proxy, "\n");
464
465   assign_stub_out_args( proxy, indent, cur );
466
467   print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n");
468   fprintf(proxy, "\n");
469   print_proxy("");
470   if (has_ret) fprintf(proxy, "_RetVal = ");
471   if (cas) fprintf(proxy, "%s_%s_Stub", iface->name, cas);
472   else
473   {
474       fprintf(proxy, "_This->lpVtbl->");
475       write_name(proxy, def);
476   }
477   fprintf(proxy, "(_This");
478
479   if (cur->args)
480   {
481       LIST_FOR_EACH_ENTRY( arg, cur->args, const var_t, entry )
482       {
483           fprintf(proxy, ", ");
484           if (arg->type->declarray)
485               fprintf(proxy, "*");
486           write_name(proxy, arg);
487       }
488   }
489   fprintf(proxy, ");\n");
490   fprintf(proxy, "\n");
491   print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n");
492   fprintf(proxy, "\n");
493
494   write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_BUFFERSIZE);
495
496   if (!is_void(get_func_return_type(cur)))
497     write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_BUFFERSIZE);
498
499   print_proxy("NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg);\n");
500
501   write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_MARSHAL);
502   fprintf(proxy, "\n");
503
504   /* marshall the return value */
505   if (!is_void(get_func_return_type(cur)))
506     write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_MARSHAL);
507
508   indent--;
509   print_proxy("}\n");
510   print_proxy("RpcFinally\n");
511   print_proxy("{\n");
512
513   write_remoting_arguments(proxy, indent+1, cur, PASS_OUT, PHASE_FREE);
514
515   if (has_full_pointer)
516     write_full_pointer_free(proxy, indent, cur);
517
518   print_proxy("}\n");
519   print_proxy("RpcEndFinally\n");
520
521   print_proxy("_pRpcMessage->BufferLength = _StubMsg.Buffer - (unsigned char *)_pRpcMessage->Buffer;\n");
522   indent--;
523
524   print_proxy("}\n");
525   print_proxy("\n");
526 }
527
528 static int write_proxy_methods(type_t *iface)
529 {
530   const func_t *cur;
531   int i = 0;
532
533   if (iface->ref) i = write_proxy_methods(iface->ref);
534   if (iface->funcs) LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) {
535     var_t *def = cur->def;
536     if (!is_callas(def->attrs)) {
537       if (i) fprintf(proxy, ",\n");
538       print_proxy( "%s_", iface->name);
539       write_name(proxy, def);
540       fprintf(proxy, "_Proxy");
541       i++;
542     }
543   }
544   return i;
545 }
546
547 static int write_stub_methods(type_t *iface)
548 {
549   const func_t *cur;
550   int i = 0;
551
552   if (iface->ref) i = write_stub_methods(iface->ref);
553   else return i; /* skip IUnknown */
554
555   if (iface->funcs) LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) {
556     var_t *def = cur->def;
557     if (!is_local(def->attrs)) {
558       if (i) fprintf(proxy,",\n");
559       print_proxy( "%s_", iface->name);
560       write_name(proxy, def);
561       fprintf(proxy, "_Stub");
562       i++;
563     }
564   }
565   return i;
566 }
567
568 static void write_proxy(type_t *iface, unsigned int *proc_offset)
569 {
570   int midx = -1, stubs;
571   const func_t *cur;
572
573   if (!iface->funcs) return;
574
575   /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */
576
577   fprintf(proxy, "/*****************************************************************************\n");
578   fprintf(proxy, " * %s interface\n", iface->name);
579   fprintf(proxy, " */\n");
580   LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry )
581   {
582     const var_t *def = cur->def;
583     if (!is_local(def->attrs)) {
584       const var_t *cas = is_callas(def->attrs);
585       const char *cname = cas ? cas->name : NULL;
586       int idx = cur->idx;
587       if (cname) {
588           const func_t *m;
589           LIST_FOR_EACH_ENTRY( m, iface->funcs, const func_t, entry )
590               if (!strcmp(m->def->name, cname))
591               {
592                   idx = m->idx;
593                   break;
594               }
595       }
596       gen_proxy(iface, cur, idx, *proc_offset);
597       gen_stub(iface, cur, cname, *proc_offset);
598       *proc_offset += get_size_procformatstring_func( cur );
599       if (midx == -1) midx = idx;
600       else if (midx != idx) error("method index mismatch in write_proxy\n");
601       midx++;
602     }
603   }
604
605   /* proxy vtable */
606   print_proxy( "static const CINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n", midx, iface->name);
607   print_proxy( "{\n");
608   indent++;
609   print_proxy( "{\n", iface->name);
610   indent++;
611   print_proxy( "&IID_%s,\n", iface->name);
612   indent--;
613   print_proxy( "},\n");
614   print_proxy( "{\n");
615   indent++;
616   write_proxy_methods(iface);
617   fprintf(proxy, "\n");
618   indent--;
619   print_proxy( "}\n");
620   indent--;
621   print_proxy( "};\n");
622   fprintf(proxy, "\n\n");
623
624   /* stub vtable */
625   print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name);
626   print_proxy( "{\n");
627   indent++;
628   stubs = write_stub_methods(iface);
629   fprintf(proxy, "\n");
630   indent--;
631   fprintf(proxy, "};\n");
632   print_proxy( "\n");
633   print_proxy( "static const CInterfaceStubVtbl _%sStubVtbl =\n", iface->name);
634   print_proxy( "{\n");
635   indent++;
636   print_proxy( "{\n");
637   indent++;
638   print_proxy( "&IID_%s,\n", iface->name);
639   print_proxy( "0,\n");
640   print_proxy( "%d,\n", stubs+3);
641   print_proxy( "&%s_table[-3],\n", iface->name);
642   indent--;
643   print_proxy( "},\n", iface->name);
644   print_proxy( "{\n");
645   indent++;
646   print_proxy( "CStdStubBuffer_METHODS\n");
647   indent--;
648   print_proxy( "}\n");
649   indent--;
650   print_proxy( "};\n");
651   print_proxy( "\n");
652 }
653
654 static int does_any_iface(const statement_list_t *stmts, type_pred_t pred)
655 {
656   const statement_t *stmt;
657
658   if (stmts)
659     LIST_FOR_EACH_ENTRY(stmt, stmts, const statement_t, entry)
660     {
661       if (stmt->type == STMT_LIBRARY)
662       {
663           if (does_any_iface(stmt->u.lib->stmts, pred))
664               return TRUE;
665       }
666       else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
667       {
668         if (pred(stmt->u.type))
669           return TRUE;
670       }
671     }
672
673   return FALSE;
674 }
675
676 int need_proxy(const type_t *iface)
677 {
678   return is_object(iface->attrs) && !is_local(iface->attrs);
679 }
680
681 int need_stub(const type_t *iface)
682 {
683   return !is_object(iface->attrs) && !is_local(iface->attrs);
684 }
685
686 int need_proxy_file(const statement_list_t *stmts)
687 {
688   return does_any_iface(stmts, need_proxy);
689 }
690
691 int need_stub_files(const statement_list_t *stmts)
692 {
693   return does_any_iface(stmts, need_stub);
694 }
695
696 static void write_proxy_stmts(const statement_list_t *stmts, unsigned int *proc_offset)
697 {
698   const statement_t *stmt;
699   if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
700   {
701     if (stmt->type == STMT_LIBRARY)
702       write_proxy_stmts(stmt->u.lib->stmts, proc_offset);
703     else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
704     {
705       if (need_proxy(stmt->u.type))
706         write_proxy(stmt->u.type, proc_offset);
707     }
708   }
709 }
710
711 static void write_proxy_iface_name_format(const statement_list_t *stmts, const char *format)
712 {
713   const statement_t *stmt;
714   if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
715   {
716     if (stmt->type == STMT_LIBRARY)
717       write_proxy_iface_name_format(stmt->u.lib->stmts, format);
718     else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
719     {
720       type_t *iface = stmt->u.type;
721       if (iface->ref && iface->funcs && need_proxy(iface))
722         fprintf(proxy, format, iface->name);
723     }
724   }
725 }
726
727 static void write_iid_lookup(const statement_list_t *stmts, const char *file_id, int *c)
728 {
729   const statement_t *stmt;
730   if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
731   {
732     if (stmt->type == STMT_LIBRARY)
733       write_iid_lookup(stmt->u.lib->stmts, file_id, c);
734     else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
735     {
736       type_t *iface = stmt->u.type;
737       if(iface->ref && iface->funcs && need_proxy(iface))
738       {
739         fprintf(proxy, "    if (!_%s_CHECK_IID(%d))\n", file_id, *c);
740         fprintf(proxy, "    {\n");
741         fprintf(proxy, "        *pIndex = %d;\n", *c);
742         fprintf(proxy, "        return 1;\n");
743         fprintf(proxy, "    }\n");
744         (*c)++;
745       }
746     }
747   }
748 }
749
750 void write_proxies(const statement_list_t *stmts)
751 {
752   int expr_eval_routines;
753   char *file_id = proxy_token;
754   int c;
755   unsigned int proc_offset = 0;
756
757   if (!do_proxies) return;
758   if (do_everything && !need_proxy_file(stmts)) return;
759
760   init_proxy(stmts);
761   if(!proxy) return;
762
763   write_proxy_stmts(stmts, &proc_offset);
764
765   expr_eval_routines = write_expr_eval_routines(proxy, proxy_token);
766   if (expr_eval_routines)
767       write_expr_eval_routine_list(proxy, proxy_token);
768   write_user_quad_list(proxy);
769   write_stubdesc(expr_eval_routines);
770
771   print_proxy( "#if !defined(__RPC_WIN32__)\n");
772   print_proxy( "#error Currently only Wine and WIN32 are supported.\n");
773   print_proxy( "#endif\n");
774   print_proxy( "\n");
775   write_procformatstring(proxy, stmts, need_proxy);
776   write_typeformatstring(proxy, stmts, need_proxy);
777
778   fprintf(proxy, "static const CInterfaceProxyVtbl* const _%s_ProxyVtblList[] =\n", file_id);
779   fprintf(proxy, "{\n");
780   write_proxy_iface_name_format(stmts, "    (const CInterfaceProxyVtbl*)&_%sProxyVtbl,\n");
781   fprintf(proxy, "    0\n");
782   fprintf(proxy, "};\n");
783   fprintf(proxy, "\n");
784
785   fprintf(proxy, "static const CInterfaceStubVtbl* const _%s_StubVtblList[] =\n", file_id);
786   fprintf(proxy, "{\n");
787   write_proxy_iface_name_format(stmts, "    (const CInterfaceStubVtbl*)&_%sStubVtbl,\n");
788   fprintf(proxy, "    0\n");
789   fprintf(proxy, "};\n");
790   fprintf(proxy, "\n");
791
792   fprintf(proxy, "static PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id);
793   fprintf(proxy, "{\n");
794   write_proxy_iface_name_format(stmts, "    \"%s\",\n");
795   fprintf(proxy, "    0\n");
796   fprintf(proxy, "};\n");
797   fprintf(proxy, "\n");
798
799   fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_%s, pIID, n)\n", file_id, file_id);
800   fprintf(proxy, "\n");
801   fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
802   fprintf(proxy, "{\n");
803   c = 0;
804   write_iid_lookup(stmts, file_id, &c);
805   fprintf(proxy, "    return 0;\n");
806   fprintf(proxy, "}\n");
807   fprintf(proxy, "\n");
808
809   fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo =\n", file_id);
810   fprintf(proxy, "{\n");
811   fprintf(proxy, "    (const PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id);
812   fprintf(proxy, "    (const PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id);
813   fprintf(proxy, "    _%s_InterfaceNamesList,\n", file_id);
814   fprintf(proxy, "    0,\n");
815   fprintf(proxy, "    &_%s_IID_Lookup,\n", file_id);
816   fprintf(proxy, "    %d,\n", c);
817   fprintf(proxy, "    1,\n");
818   fprintf(proxy, "    0,\n");
819   fprintf(proxy, "    0,\n");
820   fprintf(proxy, "    0,\n");
821   fprintf(proxy, "    0\n");
822   fprintf(proxy, "};\n");
823
824   fclose(proxy);
825 }