/* * IDL Compiler * * Copyright 2002 Ove Kaaven * Copyright 2004 Mike McCormack * * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #ifdef HAVE_UNISTD_H # include #endif #include #include #include #include #include "widl.h" #include "utils.h" #include "parser.h" #include "header.h" #include "typegen.h" #define END_OF_LIST(list) \ do { \ if (list) { \ while (NEXT_LINK(list)) \ list = NEXT_LINK(list); \ } \ } while(0) static FILE* proxy; static int indent = 0; /* FIXME: support generation of stubless proxies */ static int print_proxy( const char *format, ... ) { va_list va; int i, r; va_start( va, format ); if ( format[0] != '\n' ) for( i=0; iattrs, ATTR_OUT) && !is_attr(arg->attrs, ATTR_IN)) { print_proxy( "if(%s)\n", arg->name ); indent++; print_proxy( "MIDL_memset( %s, 0, sizeof( *%s ));\n", arg->name, arg->name ); indent--; } } } int is_var_ptr(const var_t *v) { return v->ptr_level || is_ptr(v->type); } int cant_be_null(const var_t *v) { /* Search backwards for the most recent pointer attribute. */ const attr_list_t *attrs = v->attrs; const type_t *type = v->type; if (! attrs && type) { attrs = type->attrs; type = type->ref; } while (attrs) { int t = get_attrv(attrs, ATTR_POINTERTYPE); if (t == RPC_FC_FP || t == RPC_FC_OP || t == RPC_FC_UP) return 0; if (t == RPC_FC_RP) return 1; if (type) { attrs = type->attrs; type = type->ref; } else attrs = NULL; } return 1; /* Default is RPC_FC_RP. */ } static int is_user_derived(const var_t *v) { const attr_list_t *attrs = v->attrs; const type_t *type = v->type; if (! attrs && type) { attrs = type->attrs; type = type->ref; } while (attrs) { if (is_attr(attrs, ATTR_WIREMARSHAL)) return 1; if (type) { attrs = type->attrs; type = type->ref; } else attrs = NULL; } return 0; } static void proxy_check_pointers( const var_list_t *args ) { const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { if (is_var_ptr(arg) && cant_be_null(arg)) { print_proxy( "if(!%s)\n", arg->name ); indent++; print_proxy( "RpcRaiseException(RPC_X_NULL_REF_POINTER);\n"); indent--; } } } static void marshall_size_arg( const var_t *arg ) { int index = 0; const type_t *type = arg->type; expr_t *expr; expr = get_attrp( arg->attrs, ATTR_SIZEIS ); if (expr) { print_proxy( "_StubMsg.MaxCount = ", arg->name ); write_expr(proxy, expr, 0); fprintf(proxy, ";\n\n"); print_proxy( "NdrConformantArrayBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); return; } if (is_user_derived(arg)) { print_proxy("NdrUserMarshalBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index); return; } if (is_string_type(arg->attrs, arg->ptr_level, arg->array)) { print_proxy("NdrConformantStringBufferSize( &_StubMsg, (unsigned char*)s, ", arg->name); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index); } switch( type->type ) { case RPC_FC_BYTE: case RPC_FC_CHAR: print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 1, arg->name ); break; case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: case RPC_FC_ENUM16: print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 2, arg->name ); break; case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ENUM32: print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 4, arg->name ); break; case RPC_FC_STRUCT: print_proxy( "NdrSimpleStructBufferSize(&_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index ); break; case RPC_FC_CARRAY: print_proxy( "NdrConformantArrayBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); break; case RPC_FC_BOGUS_STRUCT: print_proxy( "NdrComplexStructBufferSize(&_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index ); break; case RPC_FC_FP: { var_t temp; memset( &temp, 0, sizeof temp ); temp.type = type->ref; temp.name = arg->name; /* FIXME */ #if 0 print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name ); #endif marshall_size_arg( &temp ); } break; case RPC_FC_IP: print_proxy( "NdrPointerBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); break; default: print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); } } static void proxy_gen_marshall_size( const var_list_t *args ) { const var_t *arg; print_proxy( "_StubMsg.BufferLength = 0U;\n" ); if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { if (is_attr(arg->attrs, ATTR_IN)) { marshall_size_arg( arg ); fprintf(proxy, "\n"); } } } static void marshall_copy_arg( const var_t *arg ) { int index = 0; type_t *type = arg->type; expr_t *expr; expr = get_attrp( arg->attrs, ATTR_SIZEIS ); if (expr) { print_proxy( "_StubMsg.MaxCount = ", arg->name ); write_expr(proxy, expr, 0); fprintf(proxy, ";\n\n"); print_proxy( "NdrConformantArrayMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); return; } if (is_user_derived(arg)) { print_proxy("NdrUserMarshalMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index); return; } if (is_string_type(arg->attrs, arg->ptr_level, arg->array)) { print_proxy("NdrConformantStringMarshall( &_StubMsg, (unsigned char*)s, ", arg->name); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index); } switch( type->type ) { case RPC_FC_BYTE: case RPC_FC_CHAR: case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: case RPC_FC_ENUM16: case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ENUM32: print_proxy( "*("); write_type(proxy, arg->type, arg, arg->tname); fprintf(proxy, " *)_StubMsg.Buffer = %s;\n", arg->name ); print_proxy("_StubMsg.Buffer += sizeof("); write_type(proxy, arg->type, arg, arg->tname); fprintf(proxy, ");\n"); break; case RPC_FC_STRUCT: /* FIXME: add the format string, and set the index below */ print_proxy( "NdrSimpleStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); break; case RPC_FC_CARRAY: break; case RPC_FC_BOGUS_STRUCT: print_proxy( "NdrComplexStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index ); break; case RPC_FC_FP: { var_t temp; memset( &temp, 0, sizeof temp ); temp.type = type->ref; temp.name = arg->name; /* FIXME */ #if 0 print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name ); #endif marshall_copy_arg( &temp ); } break; case RPC_FC_IP: print_proxy( "NdrPointerMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); break; default: print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); } } static void gen_marshall_copydata( const var_list_t *args ) { const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { if (is_attr(arg->attrs, ATTR_IN)) { marshall_copy_arg( arg ); fprintf(proxy, "\n"); } } } static void gen_marshall( const var_list_t *args ) { /* generated code to determine the size of the buffer required */ proxy_gen_marshall_size( args ); /* generated code to allocate the buffer */ print_proxy( "NdrProxyGetBuffer(This, &_StubMsg);\n" ); /* generated code to copy the args into the buffer */ gen_marshall_copydata( args ); print_proxy( "\n"); } static void unmarshall_copy_arg( const var_t *arg ) { int index = 0; type_t *type = arg->type; expr_t *expr; expr = get_attrp( arg->attrs, ATTR_SIZEIS ); if (expr) { print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char**)&%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index ); return; } if (is_user_derived(arg)) { print_proxy("NdrUserMarshalUnmarshall( &_StubMsg, (unsigned char**)&%s, ", arg->name); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0 );\n", index); return; } if (is_string_type(arg->attrs, arg->ptr_level, arg->array)) { print_proxy("NdrConformantStringUnmarshall( &_StubMsg, (unsigned char**)&s, ", arg->name); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0 );\n", index); } switch( type->type ) { case RPC_FC_BYTE: case RPC_FC_CHAR: case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: case RPC_FC_ENUM16: case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ENUM32: print_proxy( "%s = *(", arg->name ); write_type(proxy, arg->type, arg, arg->tname); fprintf(proxy," *)_StubMsg.Buffer;\n"); print_proxy("_StubMsg.Buffer += sizeof("); write_type(proxy, arg->type, arg, arg->tname); fprintf(proxy, ");\n"); break; case RPC_FC_STRUCT: print_proxy( "NdrSimpleStructUnmarshall(&_StubMsg, (unsigned char**)%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index ); break; case RPC_FC_CARRAY: print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char**)&%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index ); break; case RPC_FC_BOGUS_STRUCT: print_proxy( "NdrComplexStructUnmarshall(&_StubMsg, (unsigned char**)&%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0 );\n", index ); break; case RPC_FC_FP: { var_t temp; memset( &temp, 0, sizeof temp ); temp.type = type->ref; temp.name = arg->name; /* FIXME */ #if 1 print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name ); #endif unmarshall_copy_arg( &temp ); } break; case RPC_FC_IP: print_proxy( "NdrPointerUnmarshall(&_StubMsg, (unsigned char**)&%s, ", arg->name ); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index ); break; default: print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); } } static void gen_unmarshall( var_list_t *args ) { const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { if (is_attr(arg->attrs, ATTR_OUT)) { unmarshall_copy_arg( arg ); fprintf(proxy, "\n"); } } } static void free_variable( const var_t *arg ) { var_t *constraint; int index = 0; /* FIXME */ type_t *type; expr_t *expr; expr = get_attrp( arg->attrs, ATTR_SIZEIS ); if (expr) { print_proxy( "_StubMsg.MaxCount = ", arg->name ); write_expr(proxy, expr, 0); fprintf(proxy, ";\n\n"); print_proxy( "NdrClearOutParameters( &_StubMsg, "); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index ); fprintf(proxy, "(void*)%s );\n", arg->name ); return; } type = arg->type; switch( type->type ) { case RPC_FC_BYTE: case RPC_FC_CHAR: case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: case RPC_FC_ENUM16: case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ENUM32: case RPC_FC_STRUCT: break; case RPC_FC_FP: case RPC_FC_IP: constraint = get_attrp( arg->attrs, ATTR_IIDIS ); if( constraint ) print_proxy( "_StubMsg.MaxCount = (unsigned long) ( %s );\n",constraint->name); print_proxy( "NdrClearOutParameters( &_StubMsg, "); fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index ); fprintf(proxy, "(void*)%s );\n", arg->name ); break; default: print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); } } static void proxy_free_variables( var_list_t *args ) { const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { if (is_attr(arg->attrs, ATTR_OUT)) { free_variable( arg ); fprintf(proxy, "\n"); } } } static void gen_proxy(type_t *iface, const func_t *cur, int idx) { var_t *def = cur->def; int has_ret = !is_void(def->type, def); indent = 0; write_type(proxy, def->type, def, def->tname); print_proxy( " STDMETHODCALLTYPE %s_", iface->name); write_name(proxy, def); print_proxy( "_Proxy(\n"); write_args(proxy, cur->args, iface->name, 1, TRUE); print_proxy( ")\n"); print_proxy( "{\n"); indent ++; /* local variables */ if (has_ret) { print_proxy( "" ); write_type(proxy, def->type, def, def->tname); print_proxy( " _RetVal;\n"); } print_proxy( "RPC_MESSAGE _Msg;\n" ); print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" ); print_proxy( "\n"); /* FIXME: trace */ clear_output_vars( cur->args ); print_proxy( "RpcTryExcept\n" ); print_proxy( "{\n" ); indent++; print_proxy( "NdrProxyInitialize(This, &_Msg, &_StubMsg, &Object_StubDesc, %d);\n", idx); proxy_check_pointers( cur->args ); print_proxy( "RpcTryFinally\n" ); print_proxy( "{\n" ); indent++; gen_marshall( cur->args ); print_proxy( "NdrProxySendReceive(This, &_StubMsg);\n" ); fprintf(proxy, "\n"); print_proxy("if ((_Msg.DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n"); indent++; print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" ); indent--; fprintf(proxy, "\n"); gen_unmarshall( cur->args ); if (has_ret) { /* * FIXME: We only need to round the buffer up if it could be unaligned... * We should calculate how much buffer we used and output the following * line only if necessary. */ print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n"); print_proxy( "_RetVal = *(" ); write_type(proxy, def->type, def, def->tname); fprintf(proxy, " *)_StubMsg.Buffer;\n"); print_proxy("_StubMsg.Buffer += sizeof("); write_type(proxy, def->type, def, def->tname); fprintf(proxy, ");\n"); } indent--; print_proxy( "}\n"); print_proxy( "RpcFinally\n" ); print_proxy( "{\n" ); indent++; print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" ); indent--; print_proxy( "}\n"); print_proxy( "RpcEndFinally\n" ); indent--; print_proxy( "}\n" ); print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" ); print_proxy( "{\n" ); if (has_ret) { indent++; proxy_free_variables( cur->args ); print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" ); indent--; } print_proxy( "}\n" ); print_proxy( "RpcEndExcept\n" ); if (has_ret) { print_proxy( "return _RetVal;\n" ); } indent--; print_proxy( "}\n"); print_proxy( "\n"); } static void stub_write_locals( var_list_t *args ) { int n = 0; const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { int outptr = is_attr(arg->attrs, ATTR_OUT) && ! is_attr(arg->attrs, ATTR_IN); /* create a temporary variable to store the output */ if (outptr) { var_t temp; memset( &temp, 0, sizeof temp ); temp.ptr_level = arg->ptr_level - 1; /* dereference once */ print_proxy(""); write_type(proxy, arg->type, &temp, arg->tname); fprintf(proxy, " _M%d;\n",n++); } print_proxy(""); write_type(proxy, arg->type, arg, arg->tname); fprintf(proxy, " "); write_name(proxy, arg); fprintf(proxy, ";\n"); } } static void stub_unmarshall( const var_list_t *args ) { int n = 0; const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { if (is_attr(arg->attrs, ATTR_IN)) { unmarshall_copy_arg( arg ); fprintf(proxy,"\n"); } else if (is_attr(arg->attrs, ATTR_OUT)) { type_t *type = arg->type; switch( type->type ) { case RPC_FC_STRUCT: print_proxy("MIDL_memset("); write_name(proxy, arg); fprintf(proxy,", 0, sizeof("); write_type(proxy, arg->type, arg, arg->tname); fprintf(proxy,"));\n"); break; default: print_proxy(""); write_name(proxy, arg); fprintf(proxy," = &_M%d;\n", n); print_proxy("MIDL_memset(&_M%d, 0, sizeof _M%d);\n", n, n); ++n; break; } } } } static void stub_gen_marshall_size( const var_list_t *args ) { const var_t *arg; print_proxy( "_StubMsg.BufferLength = 0U;\n" ); if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) if (is_attr(arg->attrs, ATTR_OUT)) marshall_size_arg( arg ); } static void stub_gen_marshall_copydata( const var_list_t *args ) { const var_t *arg; if (!args) return; LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) if (is_attr(arg->attrs, ATTR_OUT)) marshall_copy_arg( arg ); } static void stub_genmarshall( const var_list_t *args ) { /* FIXME: size buffer */ stub_gen_marshall_size( args ); print_proxy("NdrStubGetBuffer(This, pRpcChannelBuffer, &_StubMsg);\n"); stub_gen_marshall_copydata( args ); } static void gen_stub(type_t *iface, const func_t *cur, const char *cas) { var_t *def = cur->def; const var_t *arg; int has_ret = !is_void(def->type, def); indent = 0; print_proxy( "void __RPC_STUB %s_", iface->name); write_name(proxy, def); print_proxy( "_Stub(\n"); indent++; print_proxy( "IRpcStubBuffer* This,\n"); print_proxy( "IRpcChannelBuffer* pRpcChannelBuffer,\n"); print_proxy( "PRPC_MESSAGE _Msg,\n"); print_proxy( "DWORD* _pdwStubPhase)\n"); indent--; print_proxy( "{\n"); indent++; /* local variables */ if (has_ret) { print_proxy(""); write_type(proxy, def->type, def, def->tname); fprintf(proxy, " _RetVal;\n"); } print_proxy("%s * _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name); print_proxy("MIDL_STUB_MESSAGE _StubMsg;\n"); stub_write_locals( cur->args ); fprintf(proxy, "\n"); /* FIXME: trace */ print_proxy("NdrStubInitialize(_Msg, &_StubMsg, &Object_StubDesc, pRpcChannelBuffer);\n"); fprintf(proxy, "\n"); print_proxy("RpcTryFinally\n"); print_proxy("{\n"); indent++; print_proxy("if ((_Msg->DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n"); indent++; print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" ); indent--; fprintf(proxy, "\n"); stub_unmarshall( cur->args ); fprintf(proxy, "\n"); print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n"); fprintf(proxy, "\n"); print_proxy(""); if (has_ret) fprintf(proxy, "_RetVal = "); fprintf(proxy, "%s_", iface->name); if (cas) fprintf(proxy, "%s_Stub", cas); else write_name(proxy, def); fprintf(proxy, "(_This"); if (cur->args) { LIST_FOR_EACH_ENTRY( arg, cur->args, const var_t, entry ) { fprintf(proxy, ", "); write_name(proxy, arg); } } fprintf(proxy, ");\n"); fprintf(proxy, "\n"); print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n"); fprintf(proxy, "\n"); stub_genmarshall( cur->args ); fprintf(proxy, "\n"); if (has_ret) { /* * FIXME: We only need to round the buffer up if it could be unaligned... * We should calculate how much buffer we used and output the following * line only if necessary. */ print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n"); print_proxy( "*(" ); write_type(proxy, def->type, def, def->tname); fprintf(proxy, " *)_StubMsg.Buffer = _RetVal;\n"); print_proxy("_StubMsg.Buffer += sizeof("); write_type(proxy, def->type, def, def->tname); fprintf(proxy, ");\n"); } indent--; print_proxy("}\n"); print_proxy("RpcFinally\n"); print_proxy("{\n"); print_proxy("}\n"); print_proxy("RpcEndFinally\n"); print_proxy("_Msg->BufferLength = _StubMsg.Buffer - (unsigned char *)_Msg->Buffer;\n"); indent--; print_proxy("}\n"); print_proxy("\n"); } static int write_proxy_methods(type_t *iface) { const func_t *cur; int i = 0; if (iface->ref) i = write_proxy_methods(iface->ref); if (iface->funcs) LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) { var_t *def = cur->def; if (!is_callas(def->attrs)) { if (i) fprintf(proxy, ",\n"); print_proxy( "%s_", iface->name); write_name(proxy, def); fprintf(proxy, "_Proxy"); i++; } } return i; } static int write_stub_methods(type_t *iface) { const func_t *cur; int i = 0; if (iface->ref) i = write_stub_methods(iface->ref); else return i; /* skip IUnknown */ if (iface->funcs) LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) { var_t *def = cur->def; if (!is_local(def->attrs)) { if (i) fprintf(proxy,",\n"); print_proxy( "%s_", iface->name); write_name(proxy, def); fprintf(proxy, "_Stub"); i++; } } return i; } static void write_proxy(type_t *iface) { int midx = -1, stubs; const func_t *cur; if (!iface->funcs) return; /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */ fprintf(proxy, "/*****************************************************************************\n"); fprintf(proxy, " * %s interface\n", iface->name); fprintf(proxy, " */\n"); LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) { const var_t *def = cur->def; if (!is_local(def->attrs)) { const var_t *cas = is_callas(def->attrs); const char *cname = cas ? cas->name : NULL; int idx = cur->idx; if (cname) { const func_t *m; LIST_FOR_EACH_ENTRY( m, iface->funcs, const func_t, entry ) if (!strcmp(get_name(m->def), cname)) { idx = m->idx; break; } } gen_proxy(iface, cur, idx); gen_stub(iface, cur, cname); if (midx == -1) midx = idx; else if (midx != idx) parser_error("method index mismatch in write_proxy"); midx++; } } /* proxy vtable */ print_proxy( "const CINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n", midx, iface->name); print_proxy( "{\n"); indent++; print_proxy( "{\n", iface->name); indent++; print_proxy( "&IID_%s,\n", iface->name); indent--; print_proxy( "},\n"); print_proxy( "{\n"); indent++; write_proxy_methods(iface); fprintf(proxy, "\n"); indent--; print_proxy( "}\n"); indent--; print_proxy( "};\n"); fprintf(proxy, "\n\n"); /* stub vtable */ print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name); print_proxy( "{\n"); indent++; stubs = write_stub_methods(iface); fprintf(proxy, "\n"); indent--; fprintf(proxy, "};\n"); print_proxy( "\n"); print_proxy( "const CInterfaceStubVtbl _%sStubVtbl =\n", iface->name); print_proxy( "{\n"); indent++; print_proxy( "{\n"); indent++; print_proxy( "&IID_%s,\n", iface->name); print_proxy( "0,\n"); print_proxy( "%d,\n", stubs+3); print_proxy( "&%s_table[-3],\n", iface->name); indent--; print_proxy( "},\n", iface->name); print_proxy( "{\n"); indent++; print_proxy( "CStdStubBuffer_METHODS\n"); indent--; print_proxy( "}\n"); indent--; print_proxy( "};\n"); print_proxy( "\n"); } void write_proxies(ifref_list_t *ifaces) { ifref_t *cur; char *file_id = proxy_token; int c; if (!do_proxies) return; if (do_everything && !ifaces) return; init_proxy(ifaces); if(!proxy) return; if (ifaces) LIST_FOR_EACH_ENTRY( cur, ifaces, ifref_t, entry ) if (is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) write_proxy(cur->iface); write_stubdesc(); print_proxy( "#if !defined(__RPC_WIN32__)\n"); print_proxy( "#error Currently only Wine and WIN32 are supported.\n"); print_proxy( "#endif\n"); print_proxy( "\n"); write_procformatstring(proxy, ifaces, 1); write_typeformatstring(proxy, ifaces, 1); fprintf(proxy, "const CInterfaceProxyVtbl* _%s_ProxyVtblList[] =\n", file_id); fprintf(proxy, "{\n"); if (ifaces) LIST_FOR_EACH_ENTRY( cur, ifaces, ifref_t, entry ) if(cur->iface->ref && cur->iface->funcs && is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) fprintf(proxy, " (CInterfaceProxyVtbl*)&_%sProxyVtbl,\n", cur->iface->name); fprintf(proxy, " 0\n"); fprintf(proxy, "};\n"); fprintf(proxy, "\n"); fprintf(proxy, "const CInterfaceStubVtbl* _%s_StubVtblList[] =\n", file_id); fprintf(proxy, "{\n"); if (ifaces) LIST_FOR_EACH_ENTRY( cur, ifaces, ifref_t, entry ) if(cur->iface->ref && cur->iface->funcs && is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) fprintf(proxy, " (CInterfaceStubVtbl*)&_%sStubVtbl,\n", cur->iface->name); fprintf(proxy, " 0\n"); fprintf(proxy, "};\n"); fprintf(proxy, "\n"); fprintf(proxy, "PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id); fprintf(proxy, "{\n"); if (ifaces) LIST_FOR_EACH_ENTRY( cur, ifaces, ifref_t, entry ) if(cur->iface->ref && cur->iface->funcs && is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) fprintf(proxy, " \"%s\",\n", cur->iface->name); fprintf(proxy, " 0\n"); fprintf(proxy, "};\n"); fprintf(proxy, "\n"); fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_%s, pIID, n)\n", file_id, file_id); fprintf(proxy, "\n"); fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id); fprintf(proxy, "{\n"); c = 0; if (ifaces) LIST_FOR_EACH_ENTRY( cur, ifaces, ifref_t, entry ) if(cur->iface->ref) { fprintf(proxy, " if (!_%s_CHECK_IID(%d))\n", file_id, c); fprintf(proxy, " {\n"); fprintf(proxy, " *pIndex = %d;\n", c); fprintf(proxy, " return 1;\n"); fprintf(proxy, " }\n"); c++; } fprintf(proxy, " return 0;\n"); fprintf(proxy, "}\n"); fprintf(proxy, "\n"); fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo =\n", file_id); fprintf(proxy, "{\n"); fprintf(proxy, " (PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id); fprintf(proxy, " (PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id); fprintf(proxy, " (const PCInterfaceName*)&_%s_InterfaceNamesList,\n", file_id); fprintf(proxy, " 0,\n"); fprintf(proxy, " &_%s_IID_Lookup,\n", file_id); fprintf(proxy, " %d,\n", c); fprintf(proxy, " 1,\n"); fprintf(proxy, " 0,\n"); fprintf(proxy, " 0,\n"); fprintf(proxy, " 0,\n"); fprintf(proxy, " 0\n"); fprintf(proxy, "};\n"); fclose(proxy); }