proxy.c 33.1 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 70 71
  print_proxy( "0,\n");
  print_proxy( "0x50100a4, /* MIDL Version 5.1.164 */\n");
  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 108 109 110 111 112 113
      if (is_attr(arg->attrs, ATTR_IN)) continue;
      if (!is_attr(arg->attrs, ATTR_OUT)) continue;
      if (is_ptr(arg->type))
      {
          if (type_get_type(type_pointer_get_ref(arg->type)) == TYPE_BASIC) continue;
          if (type_get_type(type_pointer_get_ref(arg->type)) == TYPE_ENUM) continue;
      }
      print_proxy( "if (%s) MIDL_memset( %s, 0, sizeof( *%s ));\n", arg->name, arg->name, arg->name );
114 115 116
  }
}

117 118
static int need_delegation(const type_t *iface)
{
119 120
    const type_t *parent = type_iface_get_inherit( iface );
    return parent && type_iface_get_inherit(parent) && (parent->ignore || is_local( parent->attrs ));
121 122
}

123 124 125
static int get_delegation_indirect(const type_t *iface, const type_t ** delegate_to)
{
  const type_t * cur_iface;
126
  for (cur_iface = iface; cur_iface != NULL; cur_iface = type_iface_get_inherit(cur_iface))
127 128 129
    if (need_delegation(cur_iface))
    {
      if(delegate_to)
130
        *delegate_to = type_iface_get_inherit(cur_iface);
131 132 133 134 135 136 137 138 139 140
      return 1;
    }
  return 0;
}

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

141
static void free_variable( const var_t *arg, const char *local_var_prefix )
142
{
143
  unsigned int type_offset = arg->typestring_offset;
144
  type_t *type = arg->type;
145

146
  write_parameter_conf_or_var_exprs(proxy, indent, local_var_prefix, PHASE_FREE, arg, FALSE);
147

148
  switch (typegen_detect_type(type, arg->attrs, TDT_IGNORE_STRINGS))
149
  {
150 151
  case TGT_ENUM:
  case TGT_BASIC:
152 153
    break;

154
  case TGT_STRUCT:
155
    if (get_struct_fc(type) != RPC_FC_STRUCT)
156
      print_proxy("/* FIXME: %s code for %s struct type 0x%x missing */\n", __FUNCTION__, arg->name, get_struct_fc(type) );
157 158
    break;

159 160
  case TGT_IFACE_POINTER:
  case TGT_POINTER:
161 162 163 164
  case TGT_ARRAY:
    print_proxy( "NdrClearOutParameters( &__frame->_StubMsg, ");
    fprintf(proxy, "&__MIDL_TypeFormatString.Format[%u], ", type_offset );
    fprintf(proxy, "(void *)%s );\n", arg->name );
165 166 167
    break;

  default:
168
    print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type_get_type(type) );
169 170 171
  }
}

172
static void proxy_free_variables( var_list_t *args, const char *local_var_prefix )
173
{
174 175 176 177 178
  const var_t *arg;

  if (!args) return;
  LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
    if (is_attr(arg->attrs, ATTR_OUT))
179
    {
180
      free_variable( arg, local_var_prefix );
181
      fprintf(proxy, "\n");
182 183 184
    }
}

185
static void gen_proxy(type_t *iface, const var_t *func, int idx,
186
                      unsigned int proc_offset)
187
{
188 189
  var_t *retval = type_function_get_retval(func->type);
  int has_ret = !is_void(retval->type);
190 191
  int has_full_pointer = is_full_pointer_function(func);
  const char *callconv = get_attrp(func->type->attrs, ATTR_CALLCONV);
192
  const var_list_t *args = type_get_function_args(func->type);
193
  if (!callconv) callconv = "STDMETHODCALLTYPE";
194

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

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

236
  print_proxy( "RpcExceptionInit( __proxy_filter, __finally_%s_%s_Proxy );\n", iface->name, get_name(func) );
237 238
  print_proxy( "__frame->This = This;\n" );

239
  if (has_full_pointer)
240
    write_full_pointer_init(proxy, indent, func, FALSE);
241

242
  /* FIXME: trace */
243
  clear_output_vars( type_get_function_args(func->type) );
244

245 246
  print_proxy( "RpcTryExcept\n" );
  print_proxy( "{\n" );
247
  indent++;
248
  print_proxy( "NdrProxyInitialize(This, &_RpcMessage, &__frame->_StubMsg, &Object_StubDesc, %d);\n", idx);
249
  write_pointer_checks( proxy, indent, func );
250

251
  print_proxy( "RpcTryFinally\n" );
252
  print_proxy( "{\n" );
253
  indent++;
254

255
  write_remoting_arguments(proxy, indent, func, "", PASS_IN, PHASE_BUFFERSIZE);
256

257
  print_proxy( "NdrProxyGetBuffer(This, &__frame->_StubMsg);\n" );
258

259
  write_remoting_arguments(proxy, indent, func, "", PASS_IN, PHASE_MARSHAL);
260

261
  print_proxy( "NdrProxySendReceive(This, &__frame->_StubMsg);\n" );
262
  fprintf(proxy, "\n");
263 264
  print_proxy( "__frame->_StubMsg.BufferStart = _RpcMessage.Buffer;\n" );
  print_proxy( "__frame->_StubMsg.BufferEnd   = __frame->_StubMsg.BufferStart + _RpcMessage.BufferLength;\n\n" );
265 266

  print_proxy("if ((_RpcMessage.DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
267
  indent++;
268
  print_proxy("NdrConvert( &__frame->_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
269 270
  indent--;
  fprintf(proxy, "\n");
271

272
  write_remoting_arguments(proxy, indent, func, "", PASS_OUT, PHASE_UNMARSHAL);
273 274

  if (has_ret)
275
  {
276 277 278 279
      if (decl_indirect(retval->type))
          print_proxy("MIDL_memset(&%s, 0, sizeof(%s));\n", retval->name, retval->name);
      else if (is_ptr(retval->type) || is_array(retval->type))
          print_proxy("%s = 0;\n", retval->name);
280
      write_remoting_arguments(proxy, indent, func, "", PASS_RETURN, PHASE_UNMARSHAL);
281
  }
282

283 284
  indent--;
  print_proxy( "}\n");
285
  print_proxy( "RpcFinally\n" );
286
  print_proxy( "{\n" );
287
  indent++;
288
  print_proxy( "__finally_%s_%s_Proxy( __frame );\n", iface->name, get_name(func) );
289 290 291 292 293
  indent--;
  print_proxy( "}\n");
  print_proxy( "RpcEndFinally\n" );
  indent--;
  print_proxy( "}\n" );
294
  print_proxy( "RpcExcept(__frame->_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
295 296 297
  print_proxy( "{\n" );
  if (has_ret) {
    indent++;
298
    proxy_free_variables( type_get_function_args(func->type), "" );
299
    print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
300 301 302 303
    indent--;
  }
  print_proxy( "}\n" );
  print_proxy( "RpcEndExcept\n" );
304 305

  if (has_ret) {
306
    print_proxy( "return _RetVal;\n" );
307 308 309 310 311 312
  }
  indent--;
  print_proxy( "}\n");
  print_proxy( "\n");
}

313
static void gen_stub(type_t *iface, const var_t *func, const char *cas,
314
                     unsigned int proc_offset)
315
{
316
  const var_t *arg;
317
  int has_ret = !is_void(type_function_get_rettype(func->type));
318
  int has_full_pointer = is_full_pointer_function(func);
319

320 321
  if (is_interpreted_func( iface, func )) return;

322
  indent = 0;
323
  print_proxy( "struct __frame_%s_%s_Stub\n{\n", iface->name, get_name(func));
324 325 326 327
  indent++;
  print_proxy( "__DECL_EXCEPTION_FRAME\n" );
  print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n");
  print_proxy( "%s * _This;\n", iface->name );
328
  declare_stub_args( proxy, indent, func );
329 330 331
  indent--;
  print_proxy( "};\n\n" );

332 333
  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) );
334
  indent++;
335
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_OUT, PHASE_FREE);
336
  if (has_full_pointer)
337
    write_full_pointer_free(proxy, indent, func);
338 339 340
  indent--;
  print_proxy( "}\n\n" );

341
  print_proxy( "void __RPC_STUB %s_%s_Stub(\n", iface->name, get_name(func));
342 343
  indent++;
  print_proxy( "IRpcStubBuffer* This,\n");
344 345
  print_proxy( "IRpcChannelBuffer *_pRpcChannelBuffer,\n");
  print_proxy( "PRPC_MESSAGE _pRpcMessage,\n");
346
  print_proxy( "DWORD* _pdwStubPhase)\n");
347 348 349
  indent--;
  print_proxy( "{\n");
  indent++;
350
  print_proxy( "struct __frame_%s_%s_Stub __f, * const __frame = &__f;\n\n",
351
               iface->name, get_name(func) );
352 353

  print_proxy("__frame->_This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n\n", iface->name);
354 355 356

  /* FIXME: trace */

357
  print_proxy("NdrStubInitialize(_pRpcMessage, &__frame->_StubMsg, &Object_StubDesc, _pRpcChannelBuffer);\n");
358
  fprintf(proxy, "\n");
359
  print_proxy( "RpcExceptionInit( 0, __finally_%s_%s_Stub );\n", iface->name, get_name(func) );
360

361
  write_parameters_init(proxy, indent, func, "__frame->");
362

363
  print_proxy("RpcTryFinally\n");
364 365
  print_proxy("{\n");
  indent++;
366
  if (has_full_pointer)
367
    write_full_pointer_init(proxy, indent, func, TRUE);
368
  print_proxy("if ((_pRpcMessage->DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
369
  indent++;
370
  print_proxy("NdrConvert( &__frame->_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
371 372
  indent--;
  fprintf(proxy, "\n");
373

374
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_IN, PHASE_UNMARSHAL);
375
  fprintf(proxy, "\n");
376

377
  assign_stub_out_args( proxy, indent, func, "__frame->" );
378

379 380
  print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n");
  fprintf(proxy, "\n");
381
  print_proxy( "%s", has_ret ? "__frame->_RetVal = " : "" );
382
  if (cas) fprintf(proxy, "%s_%s_Stub", iface->name, cas);
383
  else fprintf(proxy, "__frame->_This->lpVtbl->%s", get_name(func));
384
  fprintf(proxy, "(__frame->_This");
385

386
  if (type_get_function_args(func->type))
387
  {
388
      LIST_FOR_EACH_ENTRY( arg, type_get_function_args(func->type), const var_t, entry )
389
          fprintf(proxy, ", %s__frame->%s", is_array(arg->type) && !type_array_is_decl_as_ptr(arg->type) ? "*" :"" , arg->name);
390 391
  }
  fprintf(proxy, ");\n");
392 393 394
  fprintf(proxy, "\n");
  print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n");
  fprintf(proxy, "\n");
395

396
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_OUT, PHASE_BUFFERSIZE);
397

398
  if (!is_void(type_function_get_rettype(func->type)))
399
    write_remoting_arguments(proxy, indent, func, "__frame->", PASS_RETURN, PHASE_BUFFERSIZE);
400

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

403
  write_remoting_arguments(proxy, indent, func, "__frame->", PASS_OUT, PHASE_MARSHAL);
404
  fprintf(proxy, "\n");
405

406
  /* marshall the return value */
407
  if (!is_void(type_function_get_rettype(func->type)))
408
    write_remoting_arguments(proxy, indent, func, "__frame->", PASS_RETURN, PHASE_MARSHAL);
409 410 411

  indent--;
  print_proxy("}\n");
412
  print_proxy("RpcFinally\n");
413
  print_proxy("{\n");
414
  indent++;
415
  print_proxy( "__finally_%s_%s_Stub( __frame );\n", iface->name, get_name(func) );
416
  indent--;
417 418
  print_proxy("}\n");
  print_proxy("RpcEndFinally\n");
419

420
  print_proxy("_pRpcMessage->BufferLength = __frame->_StubMsg.Buffer - (unsigned char *)_pRpcMessage->Buffer;\n");
421
  indent--;
422

423 424
  print_proxy("}\n");
  print_proxy("\n");
425 426
}

427 428 429 430 431 432 433 434 435 436 437
static void gen_stub_thunk( type_t *iface, const var_t *func, unsigned int proc_offset )
{
    int has_ret = !is_void( type_function_get_rettype( func->type ));
    const var_t *arg, *callas = is_callas( func->attrs );
    const var_list_t *args = type_get_function_args( func->type );

    indent = 0;
    print_proxy( "void __RPC_API %s_%s_Thunk( PMIDL_STUB_MESSAGE pStubMsg )\n",
                 iface->name, get_name(func) );
    print_proxy( "{\n");
    indent++;
438 439
    write_func_param_struct( proxy, iface, func->type,
                             "*pParamStruct = (struct _PARAM_STRUCT *)pStubMsg->StackTop", has_ret );
440 441 442 443 444 445 446 447 448 449 450 451 452
    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");
}

453
int count_methods(const type_t *iface)
454
{
455
    const statement_t *stmt;
456 457
    int count = 0;

458 459 460
    if (type_iface_get_inherit(iface))
        count = count_methods(type_iface_get_inherit(iface));

461
    STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
462 463 464
        const var_t *func = stmt->u.var;
        if (!is_callas(func->attrs)) count++;
    }
465 466 467
    return count;
}

468 469 470 471 472 473 474 475 476 477 478
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;
}

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
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));
    }
}

509
static int write_proxy_methods(type_t *iface, int skip)
510
{
511
  const statement_t *stmt;
512
  int i = 0;
513

514 515 516
  if (type_iface_get_inherit(iface))
    i = write_proxy_methods(type_iface_get_inherit(iface),
                            need_delegation(iface));
517
  STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
518 519
    const var_t *func = stmt->u.var;
    if (!is_callas(func->attrs)) {
520 521 522 523 524 525 526 527
      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 ) &&
               !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));
528 529 530 531 532 533
      i++;
    }
  }
  return i;
}

534
static int write_stub_methods(type_t *iface, int skip)
535
{
536
  const statement_t *stmt;
537
  int i = 0;
538

539 540 541 542
  if (type_iface_get_inherit(iface))
    i = write_stub_methods(type_iface_get_inherit(iface), need_delegation(iface));
  else
    return i; /* skip IUnknown */
543

544
  STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
545
    const var_t *func = stmt->u.var;
546 547 548 549 550 551 552 553 554 555
    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);
      }
556
      if (i) fprintf(proxy,",\n");
557
      if (skip || missing) print_proxy("STUB_FORWARDING_FUNCTION");
558
      else if (is_interpreted_func( iface, func ))
559
          print_proxy( "(PRPC_STUB_FUNCTION)%s", get_stub_mode() == MODE_Oif ? "NdrStubCall2" : "NdrStubCall" );
560
      else print_proxy( "%s_%s_Stub", iface->name, fname);
561 562 563 564 565 566
      i++;
    }
  }
  return i;
}

567
static void write_thunk_methods( type_t *iface, int skip )
568 569
{
    const statement_t *stmt;
570 571 572 573 574

    if (type_iface_get_inherit( iface ))
        write_thunk_methods( type_iface_get_inherit(iface), need_delegation(iface) );
    else
        return; /* skip IUnknown */
575 576 577 578

    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        var_t *func = stmt->u.var;
579 580 581 582
        const statement_t * callas_source = NULL;

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

584 585
        if (!skip && callas_source && is_interpreted_func( iface, func ))
            print_proxy( "%s_%s_Thunk,\n", iface->name, get_name(callas_source->u.var) );
586
        else
587
            print_proxy( "0, /* %s::%s */\n", iface->name, get_name(func) );
588 589 590
    }
}

591
static void write_proxy(type_t *iface, unsigned int *proc_offset)
592
{
593
  int count;
594 595
  const statement_t *stmt;
  int first_func = 1;
596
  int needs_stub_thunks = 0;
597
  int needs_inline_stubs = need_inline_stubs( iface ) || need_delegation( iface );
598

599
  STATEMENTS_FOR_EACH_FUNC(stmt, type_iface_get_stmts(iface)) {
600
    var_t *func = stmt->u.var;
601 602 603 604 605 606 607 608
    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);
609
      const char *cname = cas ? cas->name : NULL;
610
      int idx = func->type->details.function->idx;
611
      if (cname) {
612
          const statement_t *stmt2;
613
          STATEMENTS_FOR_EACH_FUNC(stmt2, type_iface_get_stmts(iface)) {
614 615
              const var_t *m = stmt2->u.var;
              if (!strcmp(m->name, cname))
616
              {
617
                  idx = m->type->details.function->idx;
618 619
                  break;
              }
620
          }
621
      }
622
      func->procstring_offset = *proc_offset;
623 624
      gen_proxy(iface, func, idx, *proc_offset);
      gen_stub(iface, func, cname, *proc_offset);
625 626 627 628 629
      if (cas && is_interpreted_func( iface, func ))
      {
          needs_stub_thunks = 1;
          gen_stub_thunk(iface, func, *proc_offset);
      }
630
      *proc_offset += get_size_procformatstring_func( iface, func );
631 632 633
    }
  }

634 635
  count = count_methods(iface);

636 637 638 639 640 641
  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" );
642

643
  /* proxy info */
644
  if (get_stub_mode() == MODE_Oif)
645 646 647 648 649 650 651 652 653 654 655 656 657 658
  {
      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" );
  }

659
  /* proxy vtable */
660 661
  print_proxy( "static %sCINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n",
               need_delegation_indirect(iface) ? "" : "const ", count, iface->name);
662 663
  print_proxy( "{\n");
  indent++;
664
  print_proxy( "{\n");
665
  indent++;
666
  if (get_stub_mode() == MODE_Oif) print_proxy( "&%s_ProxyInfo,\n", iface->name );
667 668 669
  print_proxy( "&IID_%s,\n", iface->name);
  indent--;
  print_proxy( "},\n");
670 671
  print_proxy( "{\n");
  indent++;
672
  write_proxy_methods(iface, FALSE);
673 674
  indent--;
  print_proxy( "}\n");
675
  indent--;
676 677
  print_proxy( "};\n\n");

678 679 680 681 682 683
  /* stub thunk table */
  if (needs_stub_thunks)
  {
      print_proxy( "static const STUB_THUNK %s_StubThunkTable[] =\n", iface->name);
      print_proxy( "{\n");
      indent++;
684
      write_thunk_methods( iface, 0 );
685 686 687 688
      indent--;
      print_proxy( "};\n\n");
  }

689 690 691 692 693 694 695 696
  /* 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 );
697 698 699 700
  if (needs_stub_thunks)
      print_proxy( "&%s_StubThunkTable[-3],\n", iface->name );
  else
      print_proxy( "0,\n" );
701 702 703 704 705
  print_proxy( "0,\n" );
  print_proxy( "0,\n" );
  print_proxy( "0\n" );
  indent--;
  print_proxy( "};\n\n" );
706 707

  /* stub vtable */
708 709 710 711 712 713 714 715 716 717
  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");
  }
718
  print_proxy( "static %sCInterfaceStubVtbl _%sStubVtbl =\n",
719
               need_delegation_indirect(iface) ? "" : "const ", iface->name);
720 721 722
  print_proxy( "{\n");
  indent++;
  print_proxy( "{\n");
723
  indent++;
724
  print_proxy( "&IID_%s,\n", iface->name);
725
  print_proxy( "&%s_ServerInfo,\n", iface->name );
726
  print_proxy( "%d,\n", count);
727 728
  if (needs_inline_stubs) print_proxy( "&%s_table[-3]\n", iface->name );
  else print_proxy( "0\n" );
729
  indent--;
730
  print_proxy( "},\n");
731 732
  print_proxy( "{\n");
  indent++;
733
  print_proxy( "CStdStubBuffer_%s\n", need_delegation_indirect(iface) ? "DELEGATING_METHODS" : "METHODS");
734 735
  indent--;
  print_proxy( "}\n");
736 737 738
  indent--;
  print_proxy( "};\n");
  print_proxy( "\n");
739 740
}

741
static int does_any_iface(const statement_list_t *stmts, type_pred_t pred)
742
{
743
  const statement_t *stmt;
744

745 746 747
  if (stmts)
    LIST_FOR_EACH_ENTRY(stmt, stmts, const statement_t, entry)
    {
748
      if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
749 750 751 752 753
      {
        if (pred(stmt->u.type))
          return TRUE;
      }
    }
754 755 756 757 758 759

  return FALSE;
}

int need_proxy(const type_t *iface)
{
760 761 762 763
    if (!is_object( iface )) return 0;
    if (is_local( iface->attrs )) return 0;
    if (is_attr( iface->attrs, ATTR_DISPINTERFACE )) return 0;
    return 1;
764 765 766 767
}

int need_stub(const type_t *iface)
{
768
  return !is_object(iface) && !is_local(iface->attrs);
769 770
}

771 772
int need_proxy_file(const statement_list_t *stmts)
{
773 774 775 776 777 778
    return does_any_iface(stmts, need_proxy);
}

int need_proxy_delegation(const statement_list_t *stmts)
{
    return does_any_iface(stmts, need_delegation);
779 780
}

781 782 783 784
int need_inline_stubs(const type_t *iface)
{
    const statement_t *stmt;

785
    if (get_stub_mode() == MODE_Os) return 1;
786 787 788 789

    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
    {
        const var_t *func = stmt->u.var;
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
        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;
807 808 809 810 811
        if (!is_interpreted_func( iface, func )) return 1;
    }
    return 0;
}

812 813 814 815 816
int need_stub_files(const statement_list_t *stmts)
{
  return does_any_iface(stmts, need_stub);
}

817 818 819 820 821
int need_inline_stubs_file(const statement_list_t *stmts)
{
  return does_any_iface(stmts, need_inline_stubs);
}

822 823 824 825 826
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 )
  {
827
    if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
828 829 830 831 832 833 834
    {
      if (need_proxy(stmt->u.type))
        write_proxy(stmt->u.type, proc_offset);
    }
  }
}

835
static int cmp_iid( const void *ptr1, const void *ptr2 )
836
{
837 838 839 840 841
    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) );
842 843
}

844
static void build_iface_list( const statement_list_t *stmts, type_t **ifaces[], int *count )
845 846 847 848 849 850
{
    const statement_t *stmt;

    if (!stmts) return;
    LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
    {
851
        if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
852 853
        {
            type_t *iface = stmt->u.type;
854
            if (type_iface_get_inherit(iface) && need_proxy(iface))
855
            {
856
                *ifaces = xrealloc( *ifaces, (*count + 1) * sizeof(**ifaces) );
857
                (*ifaces)[(*count)++] = iface;
858 859 860 861 862
            }
        }
    }
}

863
static type_t **sort_interfaces( const statement_list_t *stmts, int *count )
864
{
865 866 867 868 869 870
    type_t **ifaces = NULL;

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

873
static void write_proxy_routines(const statement_list_t *stmts)
874
{
875
  int expr_eval_routines;
876
  unsigned int proc_offset = 0;
877
  char *file_id = proxy_token;
878
  int i, count, have_baseiid = 0;
879 880 881
  type_t **interfaces;
  const type_t * delegate_to;

882 883 884 885 886 887 888 889 890 891 892 893 894
  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");

895
  if (does_any_iface(stmts, need_proxy_and_inline_stubs))
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
  {
      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");
  }
912 913 914

  write_formatstringsdecl(proxy, indent, stmts, need_proxy);
  write_stubdescproto();
915
  write_proxy_stmts(stmts, &proc_offset);
916

917 918 919
  expr_eval_routines = write_expr_eval_routines(proxy, proxy_token);
  if (expr_eval_routines)
      write_expr_eval_routine_list(proxy, proxy_token);
920
  write_user_quad_list(proxy);
921
  write_stubdesc(expr_eval_routines);
922

923
  print_proxy( "#if !defined(__RPC_WIN%u__)\n", pointer_size == 8 ? 64 : 32);
924 925 926
  print_proxy( "#error Currently only Wine and WIN32 are supported.\n");
  print_proxy( "#endif\n");
  print_proxy( "\n");
927 928
  write_procformatstring(proxy, stmts, need_proxy);
  write_typeformatstring(proxy, stmts, need_proxy);
929

930
  interfaces = sort_interfaces(stmts, &count);
931
  fprintf(proxy, "static const CInterfaceProxyVtbl* const _%s_ProxyVtblList[] =\n", file_id);
932
  fprintf(proxy, "{\n");
933 934
  for (i = 0; i < count; i++)
      fprintf(proxy, "    (const CInterfaceProxyVtbl*)&_%sProxyVtbl,\n", interfaces[i]->name);
935 936 937 938
  fprintf(proxy, "    0\n");
  fprintf(proxy, "};\n");
  fprintf(proxy, "\n");

939
  fprintf(proxy, "static const CInterfaceStubVtbl* const _%s_StubVtblList[] =\n", file_id);
940
  fprintf(proxy, "{\n");
941 942
  for (i = 0; i < count; i++)
      fprintf(proxy, "    &_%sStubVtbl,\n", interfaces[i]->name);
943 944 945 946
  fprintf(proxy, "    0\n");
  fprintf(proxy, "};\n");
  fprintf(proxy, "\n");

947
  fprintf(proxy, "static PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id);
948
  fprintf(proxy, "{\n");
949 950
  for (i = 0; i < count; i++)
      fprintf(proxy, "    \"%s\",\n", interfaces[i]->name);
951 952 953 954
  fprintf(proxy, "    0\n");
  fprintf(proxy, "};\n");
  fprintf(proxy, "\n");

955 956 957 958
  for (i = 0; i < count; i++)
      if ((have_baseiid = get_delegation_indirect( interfaces[i], NULL ))) break;

  if (have_baseiid)
959 960 961
  {
      fprintf(proxy, "static const IID * _%s_BaseIIDList[] =\n", file_id);
      fprintf(proxy, "{\n");
962 963
      for (i = 0; i < count; i++)
      {
964 965
          if (get_delegation_indirect(interfaces[i], &delegate_to))
              fprintf( proxy, "    &IID_%s,  /* %s */\n", delegate_to->name, interfaces[i]->name );
966 967 968
          else
              fprintf( proxy, "    0,\n" );
      }
969 970 971 972 973
      fprintf(proxy, "    0\n");
      fprintf(proxy, "};\n");
      fprintf(proxy, "\n");
  }

974
  fprintf(proxy, "static int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
975
  fprintf(proxy, "{\n");
976 977 978 979 980 981 982 983 984 985
  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");
986 987 988 989
  fprintf(proxy, "    return 0;\n");
  fprintf(proxy, "}\n");
  fprintf(proxy, "\n");

990
  fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo DECLSPEC_HIDDEN =\n", file_id);
991
  fprintf(proxy, "{\n");
992 993
  fprintf(proxy, "    (const PCInterfaceProxyVtblList*)_%s_ProxyVtblList,\n", file_id);
  fprintf(proxy, "    (const PCInterfaceStubVtblList*)_%s_StubVtblList,\n", file_id);
994
  fprintf(proxy, "    _%s_InterfaceNamesList,\n", file_id);
995 996
  if (have_baseiid) fprintf(proxy, "    _%s_BaseIIDList,\n", file_id);
  else fprintf(proxy, "    0,\n");
997
  fprintf(proxy, "    _%s_IID_Lookup,\n", file_id);
998
  fprintf(proxy, "    %d,\n", count);
999
  fprintf(proxy, "    %d,\n", get_stub_mode() == MODE_Oif ? 2 : 1);
1000 1001 1002 1003
  fprintf(proxy, "    0,\n");
  fprintf(proxy, "    0,\n");
  fprintf(proxy, "    0,\n");
  fprintf(proxy, "    0\n");
1004
  fprintf(proxy, "};\n");
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
}

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;

  if (do_win32 && do_win64)
  {
      fprintf(proxy, "\n#ifndef _WIN64\n\n");
      pointer_size = 4;
      write_proxy_routines( stmts );
      fprintf(proxy, "\n#else /* _WIN64 */\n\n");
      pointer_size = 8;
      write_proxy_routines( stmts );
      fprintf(proxy, "\n#endif /* _WIN64 */\n");
  }
  else if (do_win32)
  {
      pointer_size = 4;
      write_proxy_routines( stmts );
  }
  else if (do_win64)
  {
      pointer_size = 8;
      write_proxy_routines( stmts );
  }
1035 1036 1037

  fclose(proxy);
}