proxy.c 34.3 KB
Newer Older
1 2 3 4
/*
 * IDL Compiler
 *
 * Copyright 2002 Ove Kaaven
5
 * Copyright 2004 Mike McCormack
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 26

#include <stdio.h>
#include <stdlib.h>
27 28 29
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
30 31 32 33 34 35 36
#include <string.h>
#include <ctype.h>

#include "widl.h"
#include "utils.h"
#include "parser.h"
#include "header.h"
37
#include "typegen.h"
38
#include "expr.h"
39

40
static FILE* proxy;
41
static int indent = 0;
42

43
static void print_proxy( const char *format, ... ) __attribute__((format (printf, 1, 2)));
44
static void print_proxy( const char *format, ... )
45 46 47
{
  va_list va;
  va_start( va, format );
48
  print( proxy, indent, format, va );
49 50 51 52 53
  va_end( va );
}

static void write_stubdescproto(void)
{
54
  print_proxy( "static const MIDL_STUB_DESC Object_StubDesc;\n");
55 56 57
  print_proxy( "\n");
}

58
static void write_stubdesc(int expr_eval_routines)
59
{
60 61 62 63 64
  print_proxy( "static const MIDL_STUB_DESC Object_StubDesc =\n{\n");
  indent++;
  print_proxy( "0,\n");
  print_proxy( "NdrOleAllocate,\n");
  print_proxy( "NdrOleFree,\n");
65
  print_proxy( "{0}, 0, 0, %s, 0,\n", expr_eval_routines ? "ExprEvalRoutines" : "0");
66 67
  print_proxy( "__MIDL_TypeFormatString.Format,\n");
  print_proxy( "1, /* -error bounds_check flag */\n");
68
  print_proxy( "0x%x, /* Ndr library version */\n", get_stub_mode() == MODE_Oif ? 0x50002 : 0x10001);
69
  print_proxy( "0,\n");
70
  print_proxy( "0x50200ca, /* MIDL Version 5.2.202 */\n");
71
  print_proxy( "0,\n");
72
  print_proxy("%s,\n", list_empty(&user_type_list) ? "0" : "UserMarshalRoutines");
73 74 75 76 77 78
  print_proxy( "0,  /* notify & notify_flag routine table */\n");
  print_proxy( "1,  /* Flags */\n");
  print_proxy( "0,  /* Reserved3 */\n");
  print_proxy( "0,  /* Reserved4 */\n");
  print_proxy( "0   /* Reserved5 */\n");
  indent--;
79 80 81 82
  print_proxy( "};\n");
  print_proxy( "\n");
}

83
static void init_proxy(const statement_list_t *stmts)
84 85
{
  if (proxy) return;
86 87
  if(!(proxy = fopen(proxy_name, "w")))
    error("Could not open %s for output\n", proxy_name);
88
  print_proxy( "/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", PACKAGE_VERSION, input_name);
89
  print_proxy( "\n");
90
  print_proxy( "#define __midl_proxy\n");
91
  print_proxy( "#include \"objbase.h\"\n");
92
  print_proxy( "\n");
93 94 95 96
  print_proxy( "#ifndef DECLSPEC_HIDDEN\n");
  print_proxy( "#define DECLSPEC_HIDDEN\n");
  print_proxy( "#endif\n");
  print_proxy( "\n");
97 98
}

99
static void clear_output_vars( const var_list_t *args )
100
{
101 102 103 104 105
  const var_t *arg;

  if (!args) return;
  LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
  {
106 107
      if (is_attr(arg->attrs, ATTR_IN)) continue;
      if (!is_attr(arg->attrs, ATTR_OUT)) continue;
108
      if (is_ptr(arg->declspec.type))
109
      {
110 111
          if (type_get_type(type_pointer_get_ref_type(arg->declspec.type)) == TYPE_BASIC) continue;
          if (type_get_type(type_pointer_get_ref_type(arg->declspec.type)) == TYPE_ENUM) continue;
112
      }
113
      print_proxy( "if (%s) MIDL_memset( %s, 0, ", arg->name, arg->name );
114
      if (is_array(arg->declspec.type) && type_array_has_conformance(arg->declspec.type))
115
      {
116
          write_expr( proxy, type_array_get_conformance(arg->declspec.type), 1, 1, NULL, NULL, "" );
117 118 119
          fprintf( proxy, " * " );
      }
      fprintf( proxy, "sizeof( *%s ));\n", arg->name );
120 121 122
  }
}

123 124
static int need_delegation(const type_t *iface)
{
125 126
    const type_t *parent = type_iface_get_inherit( iface );
    return parent && type_iface_get_inherit(parent) && (parent->ignore || is_local( parent->attrs ));
127 128
}

129 130 131
static int get_delegation_indirect(const type_t *iface, const type_t ** delegate_to)
{
  const type_t * cur_iface;
132
  for (cur_iface = iface; cur_iface != NULL; cur_iface = type_iface_get_inherit(cur_iface))
133 134 135
    if (need_delegation(cur_iface))
    {
      if(delegate_to)
136
        *delegate_to = type_iface_get_inherit(cur_iface);
137 138 139 140 141 142 143 144 145 146
      return 1;
    }
  return 0;
}

static int need_delegation_indirect(const type_t *iface)
{
  return get_delegation_indirect(iface, NULL);
}

147
static void free_variable( const var_t *arg, const char *local_var_prefix )
148
{
149
  unsigned int type_offset = arg->typestring_offset;
150
  type_t *type = arg->declspec.type;
151

152
  write_parameter_conf_or_var_exprs(proxy, indent, local_var_prefix, PHASE_FREE, arg, FALSE);
153

154
  switch (typegen_detect_type(type, arg->attrs, TDT_IGNORE_STRINGS))
155
  {
156 157
  case TGT_ENUM:
  case TGT_BASIC:
158 159
    break;

160
  case TGT_STRUCT:
161
    if (get_struct_fc(type) != FC_STRUCT)
162
      print_proxy("/* FIXME: %s code for %s struct type 0x%x missing */\n", __FUNCTION__, arg->name, get_struct_fc(type) );
163 164
    break;

165 166
  case TGT_IFACE_POINTER:
  case TGT_POINTER:
167 168 169 170
  case TGT_ARRAY:
    print_proxy( "NdrClearOutParameters( &__frame->_StubMsg, ");
    fprintf(proxy, "&__MIDL_TypeFormatString.Format[%u], ", type_offset );
    fprintf(proxy, "(void *)%s );\n", arg->name );
171 172 173
    break;

  default:
174
    print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type_get_type(type) );
175 176 177
  }
}

178
static void proxy_free_variables( var_list_t *args, const char *local_var_prefix )
179
{
180 181 182 183 184
  const var_t *arg;

  if (!args) return;
  LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
    if (is_attr(arg->attrs, ATTR_OUT))
185
    {
186
      free_variable( arg, local_var_prefix );
187
      fprintf(proxy, "\n");
188 189 190
    }
}

191
static void gen_proxy(type_t *iface, const var_t *func, int idx,
192
                      unsigned int proc_offset)
193
{
194 195
  var_t *retval = type_function_get_retval(func->declspec.type);
  int has_ret = !is_void(retval->declspec.type);
196
  int has_full_pointer = is_full_pointer_function(func);
197
  const char *callconv = get_attrp(func->declspec.type->attrs, ATTR_CALLCONV);
198
  const var_list_t *args = type_function_get_args(func->declspec.type);
199
  if (!callconv) callconv = "STDMETHODCALLTYPE";
200

201
  indent = 0;
202 203
  if (is_interpreted_func( iface, func ))
  {
204
      if (get_stub_mode() == MODE_Oif && !is_callas( func->attrs )) return;
205
      write_type_decl_left(proxy, &retval->declspec);
206 207 208
      print_proxy( " %s %s_%s_Proxy(\n", callconv, iface->name, get_name(func));
      write_args(proxy, args, iface->name, 1, TRUE);
      print_proxy( ")\n");
209
      write_client_call_routine( proxy, iface, func, "Object", proc_offset );
210 211
      return;
  }
212
  print_proxy( "static void __finally_%s_%s_Proxy( struct __proxy_frame *__frame )\n",
213
               iface->name, get_name(func) );
214 215
  print_proxy( "{\n");
  indent++;
216
  if (has_full_pointer) write_full_pointer_free(proxy, indent, func);
217 218 219 220 221
  print_proxy( "NdrProxyFreeBuffer( __frame->This, &__frame->_StubMsg );\n" );
  indent--;
  print_proxy( "}\n");
  print_proxy( "\n");

222
  write_type_decl_left(proxy, &retval->declspec);
223
  print_proxy( " %s %s_%s_Proxy(\n", callconv, iface->name, get_name(func));
224
  write_args(proxy, args, iface->name, 1, TRUE);
225 226 227
  print_proxy( ")\n");
  print_proxy( "{\n");
  indent ++;
228
  print_proxy( "struct __proxy_frame __f, * const __frame = &__f;\n" );
229 230
  /* local variables */
  if (has_ret) {
231
    print_proxy( "%s", "" );
232
    write_type_decl(proxy, &retval->declspec, retval->name);
233
    fprintf( proxy, ";\n" );
234
  }
235
  print_proxy( "RPC_MESSAGE _RpcMessage;\n" );
236
  if (has_ret) {
237
    if (decl_indirect(retval->declspec.type))
238
        print_proxy("void *_p_%s = &%s;\n", retval->name, retval->name);
239
  }
240
  print_proxy( "\n");
241

242
  print_proxy( "RpcExceptionInit( __proxy_filter, __finally_%s_%s_Proxy );\n", iface->name, get_name(func) );
243 244
  print_proxy( "__frame->This = This;\n" );

245
  if (has_full_pointer)
246
    write_full_pointer_init(proxy, indent, func, FALSE);
247

248
  /* FIXME: trace */
249
  clear_output_vars( type_function_get_args(func->declspec.type) );
250

251 252
  print_proxy( "RpcTryExcept\n" );
  print_proxy( "{\n" );
253
  indent++;
254
  print_proxy( "NdrProxyInitialize(This, &_RpcMessage, &__frame->_StubMsg, &Object_StubDesc, %d);\n", idx);
255
  write_pointer_checks( proxy, indent, func );
256

257
  print_proxy( "RpcTryFinally\n" );
258
  print_proxy( "{\n" );
259
  indent++;
260

261
  write_remoting_arguments(proxy, indent, func, "", PASS_IN, PHASE_BUFFERSIZE);
262

263
  print_proxy( "NdrProxyGetBuffer(This, &__frame->_StubMsg);\n" );
264

265
  write_remoting_arguments(proxy, indent, func, "", PASS_IN, PHASE_MARSHAL);
266

267
  print_proxy( "NdrProxySendReceive(This, &__frame->_StubMsg);\n" );
268
  fprintf(proxy, "\n");
269 270
  print_proxy( "__frame->_StubMsg.BufferStart = _RpcMessage.Buffer;\n" );
  print_proxy( "__frame->_StubMsg.BufferEnd   = __frame->_StubMsg.BufferStart + _RpcMessage.BufferLength;\n\n" );
271 272

  print_proxy("if ((_RpcMessage.DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
273
  indent++;
274
  print_proxy("NdrConvert( &__frame->_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
275 276
  indent--;
  fprintf(proxy, "\n");
277

278
  write_remoting_arguments(proxy, indent, func, "", PASS_OUT, PHASE_UNMARSHAL);
279 280

  if (has_ret)
281
  {
282
      if (decl_indirect(retval->declspec.type))
283
          print_proxy("MIDL_memset(&%s, 0, sizeof(%s));\n", retval->name, retval->name);
284
      else if (is_ptr(retval->declspec.type) || is_array(retval->declspec.type))
285
          print_proxy("%s = 0;\n", retval->name);
286
      write_remoting_arguments(proxy, indent, func, "", PASS_RETURN, PHASE_UNMARSHAL);
287
  }
288

289 290
  indent--;
  print_proxy( "}\n");
291
  print_proxy( "RpcFinally\n" );
292
  print_proxy( "{\n" );
293
  indent++;
294
  print_proxy( "__finally_%s_%s_Proxy( __frame );\n", iface->name, get_name(func) );
295 296 297 298 299
  indent--;
  print_proxy( "}\n");
  print_proxy( "RpcEndFinally\n" );
  indent--;
  print_proxy( "}\n" );
300
  print_proxy( "RpcExcept(__frame->_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
301 302 303
  print_proxy( "{\n" );
  if (has_ret) {
    indent++;
304
    proxy_free_variables( type_function_get_args(func->declspec.type), "" );
305
    print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
306 307 308 309
    indent--;
  }
  print_proxy( "}\n" );
  print_proxy( "RpcEndExcept\n" );
310 311

  if (has_ret) {
312
    print_proxy( "return _RetVal;\n" );
313 314 315 316 317 318
  }
  indent--;
  print_proxy( "}\n");
  print_proxy( "\n");
}

319
static void gen_stub(type_t *iface, const var_t *func, const char *cas,
320
                     unsigned int proc_offset)
321
{
322
  const var_t *arg;
323
  int has_ret = !is_void(type_function_get_rettype(func->declspec.type));
324
  int has_full_pointer = is_full_pointer_function(func);
325

326 327
  if (is_interpreted_func( iface, func )) return;

328
  indent = 0;
329
  print_proxy( "struct __frame_%s_%s_Stub\n{\n", iface->name, get_name(func));
330 331 332 333
  indent++;
  print_proxy( "__DECL_EXCEPTION_FRAME\n" );
  print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n");
  print_proxy( "%s * _This;\n", iface->name );
334
  declare_stub_args( proxy, indent, func );
335 336 337
  indent--;
  print_proxy( "};\n\n" );

338 339
  print_proxy( "static void __finally_%s_%s_Stub(", iface->name, get_name(func) );
  print_proxy( " struct __frame_%s_%s_Stub *__frame )\n{\n", iface->name, get_name(func) );
340
  indent++;
341
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_OUT, PHASE_FREE);
342
  if (has_full_pointer)
343
    write_full_pointer_free(proxy, indent, func);
344 345 346
  indent--;
  print_proxy( "}\n\n" );

347
  print_proxy( "void __RPC_STUB %s_%s_Stub(\n", iface->name, get_name(func));
348 349
  indent++;
  print_proxy( "IRpcStubBuffer* This,\n");
350 351
  print_proxy( "IRpcChannelBuffer *_pRpcChannelBuffer,\n");
  print_proxy( "PRPC_MESSAGE _pRpcMessage,\n");
352
  print_proxy( "DWORD* _pdwStubPhase)\n");
353 354 355
  indent--;
  print_proxy( "{\n");
  indent++;
356
  print_proxy( "struct __frame_%s_%s_Stub __f, * const __frame = &__f;\n\n",
357
               iface->name, get_name(func) );
358 359

  print_proxy("__frame->_This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n\n", iface->name);
360 361 362

  /* FIXME: trace */

363
  print_proxy("NdrStubInitialize(_pRpcMessage, &__frame->_StubMsg, &Object_StubDesc, _pRpcChannelBuffer);\n");
364
  fprintf(proxy, "\n");
365
  print_proxy( "RpcExceptionInit( 0, __finally_%s_%s_Stub );\n", iface->name, get_name(func) );
366

367
  write_parameters_init(proxy, indent, func, "__frame->");
368

369
  print_proxy("RpcTryFinally\n");
370 371
  print_proxy("{\n");
  indent++;
372
  if (has_full_pointer)
373
    write_full_pointer_init(proxy, indent, func, TRUE);
374
  print_proxy("if ((_pRpcMessage->DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
375
  indent++;
376
  print_proxy("NdrConvert( &__frame->_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
377 378
  indent--;
  fprintf(proxy, "\n");
379

380
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_IN, PHASE_UNMARSHAL);
381
  fprintf(proxy, "\n");
382

383
  assign_stub_out_args( proxy, indent, func, "__frame->" );
384

385 386
  print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n");
  fprintf(proxy, "\n");
387
  print_proxy( "%s", has_ret ? "__frame->_RetVal = " : "" );
388
  if (cas) fprintf(proxy, "%s_%s_Stub", iface->name, cas);
389
  else fprintf(proxy, "__frame->_This->lpVtbl->%s", get_name(func));
390
  fprintf(proxy, "(__frame->_This");
391

392
  if (type_function_get_args(func->declspec.type))
393
  {
394
      LIST_FOR_EACH_ENTRY( arg, type_function_get_args(func->declspec.type), const var_t, entry )
395
          fprintf(proxy, ", %s__frame->%s", is_array(arg->declspec.type) && !type_array_is_decl_as_ptr(arg->declspec.type) ? "*" :"" , arg->name);
396 397
  }
  fprintf(proxy, ");\n");
398 399 400
  fprintf(proxy, "\n");
  print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n");
  fprintf(proxy, "\n");
401

402
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_OUT, PHASE_BUFFERSIZE);
403

404
  if (!is_void(type_function_get_rettype(func->declspec.type)))
405
    write_remoting_arguments(proxy, indent, func, "__frame->", PASS_RETURN, PHASE_BUFFERSIZE);
406

407
  print_proxy("NdrStubGetBuffer(This, _pRpcChannelBuffer, &__frame->_StubMsg);\n");
408

409
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_OUT, PHASE_MARSHAL);
410
  fprintf(proxy, "\n");
411

412
  /* marshall the return value */
413
  if (!is_void(type_function_get_rettype(func->declspec.type)))
414
    write_remoting_arguments(proxy, indent, func, "__frame->", PASS_RETURN, PHASE_MARSHAL);
415 416 417

  indent--;
  print_proxy("}\n");
418
  print_proxy("RpcFinally\n");
419
  print_proxy("{\n");
420
  indent++;
421
  print_proxy( "__finally_%s_%s_Stub( __frame );\n", iface->name, get_name(func) );
422
  indent--;
423 424
  print_proxy("}\n");
  print_proxy("RpcEndFinally\n");
425

426
  print_proxy("_pRpcMessage->BufferLength = __frame->_StubMsg.Buffer - (unsigned char *)_pRpcMessage->Buffer;\n");
427
  indent--;
428

429 430
  print_proxy("}\n");
  print_proxy("\n");
431 432
}

433 434
static void gen_stub_thunk( type_t *iface, const var_t *func, unsigned int proc_offset )
{
435
    int has_ret = !is_void( type_function_get_rettype( func->declspec.type ));
436
    const var_t *arg, *callas = is_callas( func->attrs );
437
    const var_list_t *args = type_function_get_args( func->declspec.type );
438 439 440 441 442 443

    indent = 0;
    print_proxy( "void __RPC_API %s_%s_Thunk( PMIDL_STUB_MESSAGE pStubMsg )\n",
                 iface->name, get_name(func) );
    print_proxy( "{\n");
    indent++;
444
    write_func_param_struct( proxy, iface, func->declspec.type,
445
                             "*pParamStruct = (struct _PARAM_STRUCT *)pStubMsg->StackTop", has_ret );
446 447 448 449 450 451 452 453 454 455 456 457 458
    print_proxy( "%s%s_%s_Stub( pParamStruct->This",
                 has_ret ? "pParamStruct->_RetVal = " : "", iface->name, callas->name );
    indent++;
    if (args) LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
    {
        fprintf( proxy, ",\n%*spParamStruct->%s", 4 * indent, "", arg->name );
    }
    fprintf( proxy, " );\n" );
    indent--;
    indent--;
    print_proxy( "}\n\n");
}

459
int count_methods(const type_t *iface)
460
{
461
    const statement_t *stmt;
462 463
    int count = 0;

464 465 466
    if (type_iface_get_inherit(iface))
        count = count_methods(type_iface_get_inherit(iface));

467
    STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
468 469 470
        const var_t *func = stmt->u.var;
        if (!is_callas(func->attrs)) count++;
    }
471 472 473
    return count;
}

474 475 476 477 478 479 480 481 482 483 484
static const statement_t * get_callas_source(const type_t * iface, const var_t * def)
{
  const statement_t * source;
  STATEMENTS_FOR_EACH_FUNC( source, type_iface_get_stmts(iface)) {
    const var_t * cas = is_callas(source->u.var->attrs );
    if (cas && !strcmp(def->name, cas->name))
      return source;
  }
  return NULL;
}

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
static void write_proxy_procformatstring_offsets( const type_t *iface, int skip )
{
    const statement_t *stmt;

    if (type_iface_get_inherit(iface))
        write_proxy_procformatstring_offsets( type_iface_get_inherit(iface), need_delegation(iface));
    else
        return;

    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        const var_t *func = stmt->u.var;
        int missing = 0;

        if (is_callas(func->attrs)) continue;
        if (is_local(func->attrs))
        {
            const statement_t * callas_source = get_callas_source(iface, func);
            if (!callas_source)
                missing = 1;
            else
                func = callas_source->u.var;
        }
        if (skip || missing)
            print_proxy( "(unsigned short)-1,  /* %s::%s */\n", iface->name, get_name(func));
        else
            print_proxy( "%u,  /* %s::%s */\n", func->procstring_offset, iface->name, get_name(func));
    }
}

515
static int write_proxy_methods(type_t *iface, int skip)
516
{
517
  const statement_t *stmt;
518
  int i = 0;
519

520 521 522
  if (type_iface_get_inherit(iface))
    i = write_proxy_methods(type_iface_get_inherit(iface),
                            need_delegation(iface));
523
  STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
524 525
    const var_t *func = stmt->u.var;
    if (!is_callas(func->attrs)) {
526 527 528
      if (skip || (is_local(func->attrs) && !get_callas_source(iface, func)))
          print_proxy( "0,  /* %s::%s */\n", iface->name, get_name(func));
      else if (is_interpreted_func( iface, func ) &&
529
               get_stub_mode() == MODE_Oif &&
530 531 532 533 534
               !is_local( func->attrs ) &&
               type_iface_get_inherit(iface))
          print_proxy( "(void *)-1,  /* %s::%s */\n", iface->name, get_name(func));
      else
          print_proxy( "%s_%s_Proxy,\n", iface->name, get_name(func));
535 536 537 538 539 540
      i++;
    }
  }
  return i;
}

541
static int write_stub_methods(type_t *iface, int skip)
542
{
543
  const statement_t *stmt;
544
  int i = 0;
545

546 547 548 549
  if (type_iface_get_inherit(iface))
    i = write_stub_methods(type_iface_get_inherit(iface), need_delegation(iface));
  else
    return i; /* skip IUnknown */
550

551
  STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
552
    const var_t *func = stmt->u.var;
553 554 555 556 557 558 559 560 561 562
    if (!is_callas(func->attrs)) {
      int missing = 0;
      const char * fname = get_name(func);
      if(is_local(func->attrs)) {
        const statement_t * callas_source = get_callas_source(iface, func);
        if(!callas_source)
          missing = 1;
        else
          fname = get_name(callas_source->u.var);
      }
563
      if (i) fprintf(proxy,",\n");
564
      if (skip || missing) print_proxy("STUB_FORWARDING_FUNCTION");
565
      else if (is_interpreted_func( iface, func ))
566
          print_proxy( "(PRPC_STUB_FUNCTION)%s", get_stub_mode() == MODE_Oif ? "NdrStubCall2" : "NdrStubCall" );
567
      else print_proxy( "%s_%s_Stub", iface->name, fname);
568 569 570 571 572 573
      i++;
    }
  }
  return i;
}

574
static void write_thunk_methods( type_t *iface, int skip )
575 576
{
    const statement_t *stmt;
577 578 579 580 581

    if (type_iface_get_inherit( iface ))
        write_thunk_methods( type_iface_get_inherit(iface), need_delegation(iface) );
    else
        return; /* skip IUnknown */
582 583 584 585

    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        var_t *func = stmt->u.var;
586 587 588 589
        const statement_t * callas_source = NULL;

        if (is_callas(func->attrs)) continue;
        if (is_local(func->attrs)) callas_source = get_callas_source(iface, func);
590

591 592
        if (!skip && callas_source && is_interpreted_func( iface, func ))
            print_proxy( "%s_%s_Thunk,\n", iface->name, get_name(callas_source->u.var) );
593
        else
594
            print_proxy( "0, /* %s::%s */\n", iface->name, get_name(func) );
595 596 597
    }
}

598
static void write_proxy(type_t *iface, unsigned int *proc_offset)
599
{
600
  int count;
601 602
  const statement_t *stmt;
  int first_func = 1;
603
  int needs_stub_thunks = 0;
604
  int needs_inline_stubs = need_inline_stubs( iface ) || need_delegation( iface );
605

606
  STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
607
    var_t *func = stmt->u.var;
608 609 610 611 612 613 614 615
    if (first_func) {
      fprintf(proxy, "/*****************************************************************************\n");
      fprintf(proxy, " * %s interface\n", iface->name);
      fprintf(proxy, " */\n");
      first_func = 0;
    }
    if (!is_local(func->attrs)) {
      const var_t *cas = is_callas(func->attrs);
616
      const char *cname = cas ? cas->name : NULL;
617
      int idx = func->func_idx;
618
      if (cname) {
619
          const statement_t *stmt2;
620
          STATEMENTS_FOR_EACH_FUNC(stmt2, type_iface_get_stmts(iface)) {
621 622
              const var_t *m = stmt2->u.var;
              if (!strcmp(m->name, cname))
623
              {
624
                  idx = m->func_idx;
625 626
                  break;
              }
627
          }
628
      }
629
      func->procstring_offset = *proc_offset;
630 631
      gen_proxy(iface, func, idx, *proc_offset);
      gen_stub(iface, func, cname, *proc_offset);
632 633 634 635 636
      if (cas && is_interpreted_func( iface, func ))
      {
          needs_stub_thunks = 1;
          gen_stub_thunk(iface, func, *proc_offset);
      }
637
      *proc_offset += get_size_procformatstring_func( iface, func );
638 639 640
    }
  }

641 642
  count = count_methods(iface);

643 644 645 646 647 648
  print_proxy( "static const unsigned short %s_FormatStringOffsetTable[] =\n", iface->name );
  print_proxy( "{\n" );
  indent++;
  write_proxy_procformatstring_offsets( iface, 0 );
  indent--;
  print_proxy( "};\n\n" );
649

650
  /* proxy info */
651
  if (get_stub_mode() == MODE_Oif)
652 653 654 655 656 657 658 659 660 661 662 663 664 665
  {
      print_proxy( "static const MIDL_STUBLESS_PROXY_INFO %s_ProxyInfo =\n", iface->name );
      print_proxy( "{\n" );
      indent++;
      print_proxy( "&Object_StubDesc,\n" );
      print_proxy( "__MIDL_ProcFormatString.Format,\n" );
      print_proxy( "&%s_FormatStringOffsetTable[-3],\n", iface->name );
      print_proxy( "0,\n" );
      print_proxy( "0,\n" );
      print_proxy( "0\n" );
      indent--;
      print_proxy( "};\n\n" );
  }

666
  /* proxy vtable */
667
  print_proxy( "static %sCINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n",
668 669
               (get_stub_mode() != MODE_Os || need_delegation_indirect(iface)) ? "" : "const ",
               count, iface->name);
670 671
  print_proxy( "{\n");
  indent++;
672
  print_proxy( "{\n");
673
  indent++;
674
  if (get_stub_mode() == MODE_Oif) print_proxy( "&%s_ProxyInfo,\n", iface->name );
675 676 677
  print_proxy( "&IID_%s,\n", iface->name);
  indent--;
  print_proxy( "},\n");
678 679
  print_proxy( "{\n");
  indent++;
680
  write_proxy_methods(iface, FALSE);
681 682
  indent--;
  print_proxy( "}\n");
683
  indent--;
684 685
  print_proxy( "};\n\n");

686 687 688 689 690 691
  /* stub thunk table */
  if (needs_stub_thunks)
  {
      print_proxy( "static const STUB_THUNK %s_StubThunkTable[] =\n", iface->name);
      print_proxy( "{\n");
      indent++;
692
      write_thunk_methods( iface, 0 );
693 694 695 696
      indent--;
      print_proxy( "};\n\n");
  }

697 698 699 700 701 702 703 704
  /* server info */
  print_proxy( "static const MIDL_SERVER_INFO %s_ServerInfo =\n", iface->name );
  print_proxy( "{\n" );
  indent++;
  print_proxy( "&Object_StubDesc,\n" );
  print_proxy( "0,\n" );
  print_proxy( "__MIDL_ProcFormatString.Format,\n" );
  print_proxy( "&%s_FormatStringOffsetTable[-3],\n", iface->name );
705 706 707 708
  if (needs_stub_thunks)
      print_proxy( "&%s_StubThunkTable[-3],\n", iface->name );
  else
      print_proxy( "0,\n" );
709 710 711 712 713
  print_proxy( "0,\n" );
  print_proxy( "0,\n" );
  print_proxy( "0\n" );
  indent--;
  print_proxy( "};\n\n" );
714 715

  /* stub vtable */
716 717 718 719 720 721 722 723 724 725
  if (needs_inline_stubs)
  {
      print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name);
      print_proxy( "{\n");
      indent++;
      write_stub_methods(iface, FALSE);
      fprintf(proxy, "\n");
      indent--;
      fprintf(proxy, "};\n\n");
  }
726
  print_proxy( "static %sCInterfaceStubVtbl _%sStubVtbl =\n",
727
               need_delegation_indirect(iface) ? "" : "const ", iface->name);
728 729 730
  print_proxy( "{\n");
  indent++;
  print_proxy( "{\n");
731
  indent++;
732
  print_proxy( "&IID_%s,\n", iface->name);
733
  print_proxy( "&%s_ServerInfo,\n", iface->name );
734
  print_proxy( "%d,\n", count);
735 736
  if (needs_inline_stubs) print_proxy( "&%s_table[-3]\n", iface->name );
  else print_proxy( "0\n" );
737
  indent--;
738
  print_proxy( "},\n");
739 740
  print_proxy( "{\n");
  indent++;
741
  print_proxy( "%s_%s\n",
742
               type_iface_get_async_iface(iface) == iface ? "CStdAsyncStubBuffer" : "CStdStubBuffer",
743
               need_delegation_indirect(iface) ? "DELEGATING_METHODS" : "METHODS");
744 745
  indent--;
  print_proxy( "}\n");
746 747 748
  indent--;
  print_proxy( "};\n");
  print_proxy( "\n");
749 750
}

751
static int does_any_iface(const statement_list_t *stmts, type_pred_t pred)
752
{
753
  const statement_t *stmt;
754

755 756 757
  if (stmts)
    LIST_FOR_EACH_ENTRY(stmt, stmts, const statement_t, entry)
    {
758
      if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
759 760 761 762 763
      {
        if (pred(stmt->u.type))
          return TRUE;
      }
    }
764 765 766 767 768 769

  return FALSE;
}

int need_proxy(const type_t *iface)
{
770 771 772 773
    if (!is_object( iface )) return 0;
    if (is_local( iface->attrs )) return 0;
    if (is_attr( iface->attrs, ATTR_DISPINTERFACE )) return 0;
    return 1;
774 775 776 777
}

int need_stub(const type_t *iface)
{
778
  return !is_object(iface) && !is_local(iface->attrs);
779 780
}

781 782
int need_proxy_file(const statement_list_t *stmts)
{
783 784 785 786 787 788
    return does_any_iface(stmts, need_proxy);
}

int need_proxy_delegation(const statement_list_t *stmts)
{
    return does_any_iface(stmts, need_delegation);
789 790
}

791 792 793 794
int need_inline_stubs(const type_t *iface)
{
    const statement_t *stmt;

795
    if (get_stub_mode() == MODE_Os) return 1;
796 797 798 799

    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        const var_t *func = stmt->u.var;
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
        if (is_local( func->attrs )) continue;
        if (!is_interpreted_func( iface, func )) return 1;
    }
    return 0;
}

static int need_proxy_and_inline_stubs(const type_t *iface)
{
    const statement_t *stmt;

    if (!need_proxy( iface )) return 0;
    if (get_stub_mode() == MODE_Os) return 1;

    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        const var_t *func = stmt->u.var;
        if (is_local( func->attrs )) continue;
817 818 819 820 821
        if (!is_interpreted_func( iface, func )) return 1;
    }
    return 0;
}

822 823 824 825 826
int need_stub_files(const statement_list_t *stmts)
{
  return does_any_iface(stmts, need_stub);
}

827 828 829 830 831
int need_inline_stubs_file(const statement_list_t *stmts)
{
  return does_any_iface(stmts, need_inline_stubs);
}

832 833 834 835 836
static void write_proxy_stmts(const statement_list_t *stmts, unsigned int *proc_offset)
{
  const statement_t *stmt;
  if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
  {
837
    if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
838
    {
839 840 841 842
      type_t *iface = stmt->u.type;
      if (need_proxy(iface))
      {
        write_proxy(iface, proc_offset);
843 844
        if (type_iface_get_async_iface(iface))
          write_proxy(type_iface_get_async_iface(iface), proc_offset);
845
      }
846 847 848 849
    }
  }
}

850
static int cmp_iid( const void *ptr1, const void *ptr2 )
851
{
852 853 854 855 856
    const type_t * const *iface1 = ptr1;
    const type_t * const *iface2 = ptr2;
    const UUID *uuid1 = get_attrp( (*iface1)->attrs, ATTR_UUID );
    const UUID *uuid2 = get_attrp( (*iface2)->attrs, ATTR_UUID );
    return memcmp( uuid1, uuid2, sizeof(UUID) );
857 858
}

859
static void build_iface_list( const statement_list_t *stmts, type_t **ifaces[], int *count )
860 861 862 863 864 865
{
    const statement_t *stmt;

    if (!stmts) return;
    LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
    {
866
        if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
867 868
        {
            type_t *iface = stmt->u.type;
869
            if (type_iface_get_inherit(iface) && need_proxy(iface))
870
            {
871
                *ifaces = xrealloc( *ifaces, (*count + 1) * sizeof(**ifaces) );
872
                (*ifaces)[(*count)++] = iface;
873
                if (type_iface_get_async_iface(iface))
874
                {
875
                    iface = type_iface_get_async_iface(iface);
876 877 878
                    *ifaces = xrealloc( *ifaces, (*count + 1) * sizeof(**ifaces) );
                    (*ifaces)[(*count)++] = iface;
                }
879 880 881 882 883
            }
        }
    }
}

884
static type_t **sort_interfaces( const statement_list_t *stmts, int *count )
885
{
886 887 888 889 890 891
    type_t **ifaces = NULL;

    *count = 0;
    build_iface_list( stmts, &ifaces, count );
    qsort( ifaces, *count, sizeof(*ifaces), cmp_iid );
    return ifaces;
892 893
}

894
static void write_proxy_routines(const statement_list_t *stmts)
895
{
896
  int expr_eval_routines;
897
  unsigned int proc_offset = 0;
898
  char *file_id = proxy_token;
899
  int i, count, have_baseiid = 0;
900
  unsigned int table_version;
901 902 903
  type_t **interfaces;
  const type_t * delegate_to;

904 905 906 907 908 909 910 911 912 913 914 915 916
  print_proxy( "#ifndef __REDQ_RPCPROXY_H_VERSION__\n");
  print_proxy( "#define __REQUIRED_RPCPROXY_H_VERSION__ %u\n", get_stub_mode() == MODE_Oif ? 475 : 440);
  print_proxy( "#endif\n");
  print_proxy( "\n");
  if (get_stub_mode() == MODE_Oif) print_proxy( "#define USE_STUBLESS_PROXY\n");
  print_proxy( "#include \"rpcproxy.h\"\n");
  print_proxy( "#ifndef __RPCPROXY_H_VERSION__\n");
  print_proxy( "#error This code needs a newer version of rpcproxy.h\n");
  print_proxy( "#endif /* __RPCPROXY_H_VERSION__ */\n");
  print_proxy( "\n");
  print_proxy( "#include \"%s\"\n", header_name);
  print_proxy( "\n");

917
  if (does_any_iface(stmts, need_proxy_and_inline_stubs))
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
  {
      write_exceptions( proxy );
      print_proxy( "\n");
      print_proxy( "struct __proxy_frame\n");
      print_proxy( "{\n");
      print_proxy( "    __DECL_EXCEPTION_FRAME\n");
      print_proxy( "    MIDL_STUB_MESSAGE _StubMsg;\n");
      print_proxy( "    void             *This;\n");
      print_proxy( "};\n");
      print_proxy( "\n");
      print_proxy("static int __proxy_filter( struct __proxy_frame *__frame )\n");
      print_proxy( "{\n");
      print_proxy( "    return (__frame->_StubMsg.dwStubPhase != PROXY_SENDRECEIVE);\n");
      print_proxy( "}\n");
      print_proxy( "\n");
  }
934 935 936

  write_formatstringsdecl(proxy, indent, stmts, need_proxy);
  write_stubdescproto();
937
  write_proxy_stmts(stmts, &proc_offset);
938

939 940 941
  expr_eval_routines = write_expr_eval_routines(proxy, proxy_token);
  if (expr_eval_routines)
      write_expr_eval_routine_list(proxy, proxy_token);
942
  write_user_quad_list(proxy);
943
  write_stubdesc(expr_eval_routines);
944

945
  print_proxy( "#if !defined(__RPC_WIN%u__)\n", pointer_size == 8 ? 64 : 32);
946
  print_proxy( "#error Invalid build platform for this proxy.\n");
947 948
  print_proxy( "#endif\n");
  print_proxy( "\n");
949 950
  write_procformatstring(proxy, stmts, need_proxy);
  write_typeformatstring(proxy, stmts, need_proxy);
951

952
  interfaces = sort_interfaces(stmts, &count);
953
  fprintf(proxy, "static const CInterfaceProxyVtbl* const _%s_ProxyVtblList[] =\n", file_id);
954
  fprintf(proxy, "{\n");
955 956
  for (i = 0; i < count; i++)
      fprintf(proxy, "    (const CInterfaceProxyVtbl*)&_%sProxyVtbl,\n", interfaces[i]->name);
957 958 959 960
  fprintf(proxy, "    0\n");
  fprintf(proxy, "};\n");
  fprintf(proxy, "\n");

961
  fprintf(proxy, "static const CInterfaceStubVtbl* const _%s_StubVtblList[] =\n", file_id);
962
  fprintf(proxy, "{\n");
963 964
  for (i = 0; i < count; i++)
      fprintf(proxy, "    &_%sStubVtbl,\n", interfaces[i]->name);
965 966 967 968
  fprintf(proxy, "    0\n");
  fprintf(proxy, "};\n");
  fprintf(proxy, "\n");

969
  fprintf(proxy, "static PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id);
970
  fprintf(proxy, "{\n");
971 972
  for (i = 0; i < count; i++)
      fprintf(proxy, "    \"%s\",\n", interfaces[i]->name);
973 974 975 976
  fprintf(proxy, "    0\n");
  fprintf(proxy, "};\n");
  fprintf(proxy, "\n");

977 978 979 980
  for (i = 0; i < count; i++)
      if ((have_baseiid = get_delegation_indirect( interfaces[i], NULL ))) break;

  if (have_baseiid)
981 982 983
  {
      fprintf(proxy, "static const IID * _%s_BaseIIDList[] =\n", file_id);
      fprintf(proxy, "{\n");
984 985
      for (i = 0; i < count; i++)
      {
986 987
          if (get_delegation_indirect(interfaces[i], &delegate_to))
              fprintf( proxy, "    &IID_%s,  /* %s */\n", delegate_to->name, interfaces[i]->name );
988 989 990
          else
              fprintf( proxy, "    0,\n" );
      }
991 992 993 994 995
      fprintf(proxy, "    0\n");
      fprintf(proxy, "};\n");
      fprintf(proxy, "\n");
  }

996
  fprintf(proxy, "static int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
997
  fprintf(proxy, "{\n");
998 999 1000 1001 1002 1003 1004 1005 1006 1007
  fprintf(proxy, "    int low = 0, high = %d;\n", count - 1);
  fprintf(proxy, "\n");
  fprintf(proxy, "    while (low <= high)\n");
  fprintf(proxy, "    {\n");
  fprintf(proxy, "        int pos = (low + high) / 2;\n");
  fprintf(proxy, "        int res = IID_GENERIC_CHECK_IID(_%s, pIID, pos);\n", file_id);
  fprintf(proxy, "        if (!res) { *pIndex = pos; return 1; }\n");
  fprintf(proxy, "        if (res > 0) low = pos + 1;\n");
  fprintf(proxy, "        else high = pos - 1;\n");
  fprintf(proxy, "    }\n");
1008 1009 1010 1011
  fprintf(proxy, "    return 0;\n");
  fprintf(proxy, "}\n");
  fprintf(proxy, "\n");

1012 1013 1014
  table_version = get_stub_mode() == MODE_Oif ? 2 : 1;
  for (i = 0; i < count; i++)
  {
1015
      if (type_iface_get_async_iface(interfaces[i]) != interfaces[i]) continue;
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
      if (table_version != 6)
      {
          fprintf(proxy, "static const IID *_AsyncInterfaceTable[] =\n");
          fprintf(proxy, "{\n");
          table_version = 6;
      }
      fprintf(proxy, "    &IID_%s,\n", interfaces[i]->name);
      fprintf(proxy, "    (IID*)(LONG_PTR)-1,\n");
  }
  if (table_version == 6)
  {
      fprintf(proxy, "    0\n");
      fprintf(proxy, "};\n");
      fprintf(proxy, "\n");
  }

1032
  fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo DECLSPEC_HIDDEN =\n", file_id);
1033
  fprintf(proxy, "{\n");
1034 1035
  fprintf(proxy, "    (const PCInterfaceProxyVtblList*)_%s_ProxyVtblList,\n", file_id);
  fprintf(proxy, "    (const PCInterfaceStubVtblList*)_%s_StubVtblList,\n", file_id);
1036
  fprintf(proxy, "    _%s_InterfaceNamesList,\n", file_id);
1037 1038
  if (have_baseiid) fprintf(proxy, "    _%s_BaseIIDList,\n", file_id);
  else fprintf(proxy, "    0,\n");
1039
  fprintf(proxy, "    _%s_IID_Lookup,\n", file_id);
1040
  fprintf(proxy, "    %d,\n", count);
1041 1042
  fprintf(proxy, "    %u,\n", table_version);
  fprintf(proxy, "    %s,\n", table_version == 6 ? "_AsyncInterfaceTable" : "0");
1043 1044 1045
  fprintf(proxy, "    0,\n");
  fprintf(proxy, "    0,\n");
  fprintf(proxy, "    0\n");
1046
  fprintf(proxy, "};\n");
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
}

void write_proxies(const statement_list_t *stmts)
{
  if (!do_proxies) return;
  if (do_everything && !need_proxy_file(stmts)) return;

  init_proxy(stmts);
  if(!proxy) return;

1057
  write_proxy_routines( stmts );
1058 1059
  fclose(proxy);
}