[TOOLS]
[reactos.git] / reactos / tools / widl / typegen.c
index 244baea..dfc5a50 100644 (file)
 #define ROUNDING(size, alignment) (((alignment) - 1) - (((size) + ((alignment) - 1)) & ((alignment) - 1)))
 
 static const type_t *current_structure;
+static const var_t *current_func;
 static const type_t *current_iface;
 
 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
 struct expr_eval_routine
 {
-    struct list entry;
-    const type_t *structure;
-    unsigned int baseoff;
+    struct list   entry;
+    const type_t *iface;
+    const type_t *cont_type;
+    char         *name;
+    unsigned int  baseoff;
     const expr_t *expr;
 };
 
@@ -66,6 +69,19 @@ enum type_context
     TYPE_CONTEXT_CONTAINER_NO_POINTERS,
 };
 
+/* parameter flags in Oif mode */
+static const unsigned short MustSize = 0x0001;
+static const unsigned short MustFree = 0x0002;
+static const unsigned short IsPipe = 0x0004;
+static const unsigned short IsIn = 0x0008;
+static const unsigned short IsOut = 0x0010;
+static const unsigned short IsReturn = 0x0020;
+static const unsigned short IsBasetype = 0x0040;
+static const unsigned short IsByValue = 0x0080;
+static const unsigned short IsSimpleRef = 0x0100;
+/* static const unsigned short IsDontCallFreeInst = 0x0200; */
+/* static const unsigned short SaveForAsyncFinish = 0x0400; */
+
 static unsigned int field_memsize(const type_t *type, unsigned int *offset);
 static unsigned int fields_memsize(const var_list_t *fields, unsigned int *align);
 static unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *align);
@@ -74,8 +90,12 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
                                 const char *name, int write_ptr, unsigned int *tfsoff);
 static const var_t *find_array_or_string_in_struct(const type_t *type);
 static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
-                               type_t *type, int toplevel_param,
-                               const char *name, unsigned int *typestring_offset);
+                                     type_t *type, enum type_context context,
+                                     const char *name, unsigned int *typestring_offset);
+static unsigned int get_required_buffer_size_type( const type_t *type, const char *name,
+                                                   const attr_list_t *attrs, int toplevel_param,
+                                                   unsigned int *alignment );
+static unsigned int get_function_buffer_size( const var_t *func, enum pass pass );
 
 static const char *string_of_type(unsigned char type)
 {
@@ -203,6 +223,28 @@ unsigned char get_basic_fc(const type_t *type)
     return 0;
 }
 
+static unsigned char get_basic_fc_signed(const type_t *type)
+{
+    switch (type_basic_get_type(type))
+    {
+    case TYPE_BASIC_INT8: return RPC_FC_SMALL;
+    case TYPE_BASIC_INT16: return RPC_FC_SHORT;
+    case TYPE_BASIC_INT32: return RPC_FC_LONG;
+    case TYPE_BASIC_INT64: return RPC_FC_HYPER;
+    case TYPE_BASIC_INT: return RPC_FC_LONG;
+    case TYPE_BASIC_INT3264: return RPC_FC_INT3264;
+    case TYPE_BASIC_BYTE: return RPC_FC_BYTE;
+    case TYPE_BASIC_CHAR: return RPC_FC_CHAR;
+    case TYPE_BASIC_WCHAR: return RPC_FC_WCHAR;
+    case TYPE_BASIC_HYPER: return RPC_FC_HYPER;
+    case TYPE_BASIC_FLOAT: return RPC_FC_FLOAT;
+    case TYPE_BASIC_DOUBLE: return RPC_FC_DOUBLE;
+    case TYPE_BASIC_ERROR_STATUS_T: return RPC_FC_ERROR_STATUS_T;
+    case TYPE_BASIC_HANDLE: return RPC_FC_BIND_PRIMITIVE;
+    }
+    return 0;
+}
+
 static inline unsigned int clamp_align(unsigned int align)
 {
     unsigned int packing = (pointer_size == 4) ? win32_packing : win64_packing;
@@ -236,6 +278,18 @@ unsigned char get_pointer_fc(const type_t *type, const attr_list_t *attrs, int t
         return type_array_get_ptr_default_fc(type);
 }
 
+static unsigned char get_pointer_fc_context( const type_t *type, const attr_list_t *attrs,
+                                             enum type_context context )
+{
+    int pointer_fc = get_pointer_fc(type, attrs, context == TYPE_CONTEXT_TOPLEVELPARAM);
+
+    if (pointer_fc == RPC_FC_UP && is_attr( attrs, ATTR_OUT ) &&
+        context == TYPE_CONTEXT_PARAM && is_object( current_iface ))
+        pointer_fc = RPC_FC_OP;
+
+    return pointer_fc;
+}
+
 static unsigned char get_enum_fc(const type_t *type)
 {
     assert(type_get_type(type) == TYPE_ENUM);
@@ -319,6 +373,23 @@ enum typegen_type typegen_detect_type(const type_t *type, const attr_list_t *att
     return TGT_INVALID;
 }
 
+static int cant_be_null(const var_t *v)
+{
+    switch (typegen_detect_type(v->type, v->attrs, TDT_IGNORE_STRINGS))
+    {
+    case TGT_ARRAY:
+        if (!type_array_is_decl_as_ptr( v->type )) return 0;
+        /* fall through */
+    case TGT_POINTER:
+        return (get_pointer_fc(v->type, v->attrs, TRUE) == RPC_FC_RP);
+    case TGT_CTXT_HANDLE_POINTER:
+        return TRUE;
+    default:
+        return 0;
+    }
+
+}
+
 static int get_padding(const var_list_t *fields)
 {
     unsigned short offset = 0;
@@ -342,6 +413,65 @@ static int get_padding(const var_list_t *fields)
     return ROUNDING(offset, salign);
 }
 
+static unsigned int get_stack_size( const type_t *type, const attr_list_t *attrs, int *by_value )
+{
+    unsigned int stack_size;
+    int by_val;
+
+    switch (typegen_detect_type( type, attrs, TDT_ALL_TYPES ))
+    {
+    case TGT_BASIC:
+    case TGT_ENUM:
+    case TGT_RANGE:
+    case TGT_STRUCT:
+    case TGT_UNION:
+    case TGT_USER_TYPE:
+        stack_size = type_memsize( type );
+        by_val = (pointer_size < 8 || stack_size <= pointer_size); /* FIXME: should be platform-specific */
+        break;
+    default:
+        by_val = 0;
+        break;
+    }
+    if (!by_val) stack_size = pointer_size;
+    if (by_value) *by_value = by_val;
+    return ROUND_SIZE( stack_size, pointer_size );
+}
+
+static unsigned char get_contexthandle_flags( const type_t *iface, const attr_list_t *attrs,
+                                              const type_t *type )
+{
+    unsigned char flags = 0;
+
+    if (is_attr(iface->attrs, ATTR_STRICTCONTEXTHANDLE)) flags |= NDR_STRICT_CONTEXT_HANDLE;
+
+    if (is_ptr(type) &&
+        !is_attr( type->attrs, ATTR_CONTEXTHANDLE ) &&
+        !is_attr( attrs, ATTR_CONTEXTHANDLE ))
+        flags |= 0x80;
+
+    if (is_attr(attrs, ATTR_IN))
+    {
+        flags |= 0x40;
+        if (!is_attr(attrs, ATTR_OUT)) flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
+    }
+    if (is_attr(attrs, ATTR_OUT)) flags |= 0x20;
+
+    return flags;
+}
+
+static unsigned int get_rpc_flags( const attr_list_t *attrs )
+{
+    unsigned int flags = 0;
+
+    if (is_attr( attrs, ATTR_IDEMPOTENT )) flags |= 0x0001;
+    if (is_attr( attrs, ATTR_BROADCAST )) flags |= 0x0002;
+    if (is_attr( attrs, ATTR_MAYBE )) flags |= 0x0004;
+    if (is_attr( attrs, ATTR_MESSAGE )) flags |= 0x0100;
+    if (is_attr( attrs, ATTR_ASYNC )) flags |= 0x4000;
+    return flags;
+}
+
 unsigned char get_struct_fc(const type_t *type)
 {
   int has_pointer = 0;
@@ -822,10 +952,230 @@ int decl_indirect(const type_t *t)
             type_get_type(t) != TYPE_ARRAY);
 }
 
-static unsigned int write_procformatstring_type(FILE *file, int indent,
-                                                const type_t *type,
-                                                const attr_list_t *attrs,
-                                                int is_return)
+static unsigned char get_parameter_fc( const type_t *type, const attr_list_t *attrs, int is_return,
+                                       unsigned short *flags, unsigned int *stack_size,
+                                       unsigned int *typestring_offset )
+{
+    unsigned int alignment, server_size = 0, buffer_size = 0;
+    unsigned char fc = 0;
+    int is_byval;
+    int is_in = is_attr(attrs, ATTR_IN);
+    int is_out = is_attr(attrs, ATTR_OUT);
+
+    if (is_return) is_out = TRUE;
+    else if (!is_in && !is_out) is_in = TRUE;
+
+    *flags = 0;
+    *stack_size = get_stack_size( type, attrs, &is_byval );
+    *typestring_offset = type->typestring_offset;
+
+    if (is_in)     *flags |= IsIn;
+    if (is_out)    *flags |= IsOut;
+    if (is_return) *flags |= IsReturn;
+
+    if (!is_string_type( attrs, type ))
+        buffer_size = get_required_buffer_size_type( type, NULL, attrs, TRUE, &alignment );
+
+    switch (typegen_detect_type( type, attrs, TDT_ALL_TYPES ))
+    {
+    case TGT_BASIC:
+        *flags |= IsBasetype;
+        fc = get_basic_fc_signed( type );
+        if (fc == RPC_FC_BIND_PRIMITIVE)
+        {
+            buffer_size = 4;  /* actually 0 but avoids setting MustSize */
+            fc = RPC_FC_LONG;
+        }
+        break;
+    case TGT_ENUM:
+        *flags |= IsBasetype;
+        fc = get_enum_fc( type );
+        break;
+    case TGT_RANGE:
+        *flags |= IsByValue;
+        break;
+    case TGT_STRUCT:
+    case TGT_UNION:
+    case TGT_USER_TYPE:
+        *flags |= MustFree | (is_byval ? IsByValue : IsSimpleRef);
+        break;
+    case TGT_IFACE_POINTER:
+        *flags |= MustFree;
+        break;
+    case TGT_ARRAY:
+        *flags |= MustFree;
+        if (type_array_is_decl_as_ptr(type) && type->details.array.ptr_tfsoff &&
+            get_pointer_fc( type, attrs, !is_return ) == RPC_FC_RP)
+            *flags |= IsSimpleRef;
+        break;
+    case TGT_STRING:
+        *flags |= MustFree;
+        if (is_declptr( type ) && get_pointer_fc( type, attrs, !is_return ) == RPC_FC_RP)
+        {
+            /* skip over pointer description straight to string description */
+            if (is_conformant_array( type )) *typestring_offset += 4;
+            else *typestring_offset += 2;
+            *flags |= IsSimpleRef;
+        }
+        break;
+    case TGT_CTXT_HANDLE_POINTER:
+        *flags |= IsSimpleRef;
+        *typestring_offset += 4;
+        /* fall through */
+    case TGT_CTXT_HANDLE:
+        buffer_size = 20;
+        break;
+    case TGT_POINTER:
+        if (get_pointer_fc( type, attrs, !is_return ) == RPC_FC_RP)
+        {
+            const type_t *ref = type_pointer_get_ref( type );
+
+            if (!is_string_type( attrs, ref ))
+                buffer_size = get_required_buffer_size_type( ref, NULL, NULL, TRUE, &alignment );
+
+            switch (typegen_detect_type( ref, NULL, TDT_ALL_TYPES ))
+            {
+            case TGT_BASIC:
+                *flags |= IsSimpleRef | IsBasetype;
+                fc = get_basic_fc( ref );
+                if (!is_in && is_out) server_size = pointer_size;
+                break;
+            case TGT_ENUM:
+                if ((fc = get_enum_fc( ref )) == RPC_FC_ENUM32)
+                {
+                    *flags |= IsSimpleRef | IsBasetype;
+                    if (!is_in && is_out) server_size = pointer_size;
+                }
+                else
+                {
+                    server_size = pointer_size;
+                }
+                break;
+            case TGT_UNION:
+            case TGT_USER_TYPE:
+            case TGT_RANGE:
+                *flags |= IsSimpleRef | MustFree;
+                *typestring_offset = ref->typestring_offset;
+                if (!is_in && is_out) server_size = type_memsize( ref );
+                break;
+            case TGT_STRING:
+            case TGT_POINTER:
+            case TGT_ARRAY:
+            case TGT_CTXT_HANDLE:
+            case TGT_CTXT_HANDLE_POINTER:
+                *flags |= MustFree;
+                server_size = pointer_size;
+                break;
+            case TGT_IFACE_POINTER:
+                *flags |= MustFree;
+                if (is_in && is_out) server_size = pointer_size;
+                break;
+            case TGT_STRUCT:
+                *flags |= IsSimpleRef | MustFree;
+                *typestring_offset = ref->typestring_offset;
+                switch (get_struct_fc(ref))
+                {
+                case RPC_FC_STRUCT:
+                case RPC_FC_PSTRUCT:
+                case RPC_FC_BOGUS_STRUCT:
+                    if (!is_in && is_out) server_size = type_memsize( ref );
+                    break;
+                default:
+                    break;
+                }
+                break;
+            case TGT_INVALID:
+                assert(0);
+            }
+        }
+        else  /* not ref pointer */
+        {
+            *flags |= MustFree;
+        }
+        break;
+    case TGT_INVALID:
+        assert(0);
+    }
+
+    if (!buffer_size) *flags |= MustSize;
+
+    if (server_size)
+    {
+        server_size = (server_size + 7) / 8;
+        if (server_size < 8) *flags |= server_size << 13;
+    }
+    return fc;
+}
+
+static unsigned char get_func_oi2_flags( const var_t *func )
+{
+    const var_t *var;
+    var_list_t *args = type_get_function_args( func->type );
+    type_t *ret_type = type_function_get_rettype( func->type );
+    unsigned char oi2_flags = 0x40;  /* HasExtensions */
+    unsigned short flags;
+    unsigned int stack_size, typestring_offset;
+
+    if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
+    {
+        get_parameter_fc( var->type, var->attrs, 0, &flags, &stack_size, &typestring_offset );
+        if (flags & MustSize)
+        {
+            if (flags & IsIn) oi2_flags |= 0x02; /* ClientMustSize */
+            if (flags & IsOut) oi2_flags |= 0x01;  /* ServerMustSize */
+        }
+    }
+
+    if (!is_void( ret_type ))
+    {
+        oi2_flags |= 0x04;  /* HasRet */
+        get_parameter_fc( ret_type, NULL, 1, &flags, &stack_size, &typestring_offset );
+        if (flags & MustSize) oi2_flags |= 0x01;  /* ServerMustSize */
+    }
+    return oi2_flags;
+}
+
+static unsigned int write_new_procformatstring_type(FILE *file, int indent,
+                                                    const type_t *type,
+                                                    const attr_list_t *attrs,
+                                                    int is_return, unsigned int *stack_offset)
+{
+    char buffer[64];
+    unsigned int stack_size, typestring_offset;
+    unsigned short flags;
+    unsigned char fc = get_parameter_fc( type, attrs, is_return, &flags, &stack_size, &typestring_offset );
+
+    strcpy( buffer, "/* flags:" );
+    if (flags & MustSize) strcat( buffer, " must size," );
+    if (flags & MustFree) strcat( buffer, " must free," );
+    if (flags & IsPipe) strcat( buffer, " pipe," );
+    if (flags & IsIn) strcat( buffer, " in," );
+    if (flags & IsOut) strcat( buffer, " out," );
+    if (flags & IsReturn) strcat( buffer, " return," );
+    if (flags & IsBasetype) strcat( buffer, " base type," );
+    if (flags & IsByValue) strcat( buffer, " by value," );
+    if (flags & IsSimpleRef) strcat( buffer, " simple ref," );
+    if (flags >> 13) sprintf( buffer + strlen(buffer), " srv size=%u,", (flags >> 13) * 8 );
+    strcpy( buffer + strlen( buffer ) - 1, " */" );
+    print_file( file, indent, "NdrFcShort(0x%hx),\t%s\n", flags, buffer );
+    print_file( file, indent, "NdrFcShort(0x%hx),      /* stack offset = %hu */\n",
+                *stack_offset, *stack_offset );
+    if (flags & IsBasetype)
+    {
+        print_file( file, indent, "0x%02x,     /* %s */\n", fc, string_of_type(fc) );
+        print_file( file, indent, "0x0,\n" );
+    }
+    else
+        print_file( file, indent, "NdrFcShort(0x%x),   /* type offset = %u */\n",
+                    typestring_offset, typestring_offset );
+    *stack_offset += max( stack_size, pointer_size );
+    return 6;
+}
+
+static unsigned int write_old_procformatstring_type(FILE *file, int indent,
+                                                    const type_t *type,
+                                                    const attr_list_t *attrs,
+                                                    int is_return, int is_interpreted)
 {
     unsigned int size;
 
@@ -850,7 +1200,7 @@ static unsigned int write_procformatstring_type(FILE *file, int indent,
         }
         else
         {
-            fc = get_basic_fc(type);
+            fc = get_basic_fc_signed(type);
 
             if (fc == RPC_FC_BIND_PRIMITIVE)
                 fc = RPC_FC_IGNORE;
@@ -862,6 +1212,13 @@ static unsigned int write_procformatstring_type(FILE *file, int indent,
     }
     else
     {
+        unsigned short offset = type->typestring_offset;
+
+        if (is_interpreted && is_array(type) &&
+            type_array_is_decl_as_ptr(type) &&
+            type->details.array.ptr_tfsoff)
+            offset = type->details.array.ptr_tfsoff;
+
         if (is_return)
             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
         else if (is_in && is_out)
@@ -871,17 +1228,206 @@ static unsigned int write_procformatstring_type(FILE *file, int indent,
         else
             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
 
-        print_file(file, indent, "0x01,\n");
-        print_file(file, indent, "NdrFcShort(0x%x),    /* type offset = %u */\n",
-                   type->typestring_offset, type->typestring_offset);
+        size = get_stack_size( type, attrs, NULL );
+        print_file(file, indent, "0x%02x,\n", size / pointer_size );
+        print_file(file, indent, "NdrFcShort(0x%x),    /* type offset = %u */\n", offset, offset);
         size = 4; /* includes param type prefix */
     }
     return size;
 }
 
-static void write_procformatstring_func( FILE *file, int indent,
-                                         const var_t *func, unsigned int *offset )
+int is_interpreted_func( const type_t *iface, const var_t *func )
+{
+    const char *str;
+    const var_t *var;
+    const var_list_t *args = type_get_function_args( func->type );
+    const type_t *ret_type = type_function_get_rettype( func->type );
+
+    if (type_get_type( ret_type ) == TYPE_BASIC)
+    {
+        switch (type_basic_get_type( ret_type ))
+        {
+        case TYPE_BASIC_INT64:
+        case TYPE_BASIC_HYPER:
+            /* return value must fit in a long_ptr */
+            if (pointer_size < 8) return 0;
+            break;
+        case TYPE_BASIC_FLOAT:
+        case TYPE_BASIC_DOUBLE:
+            /* floating point values can't be returned */
+            return 0;
+        default:
+            break;
+        }
+    }
+    if (get_stub_mode() != MODE_Oif && args)
+    {
+        LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
+            switch (type_get_type( var->type ))
+            {
+            case TYPE_BASIC:
+                switch (type_basic_get_type( var->type ))
+                {
+                /* floating point arguments are not supported in Oi mode */
+                case TYPE_BASIC_FLOAT:  return 0;
+                case TYPE_BASIC_DOUBLE: return 0;
+                default: break;
+                }
+                break;
+            /* unions passed by value are not supported in Oi mode */
+            case TYPE_UNION: return 0;
+            case TYPE_ENCAPSULATED_UNION: return 0;
+            default: break;
+            }
+    }
+
+    if ((str = get_attrp( func->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
+    if ((str = get_attrp( iface->attrs, ATTR_OPTIMIZE ))) return !strcmp( str, "i" );
+    return (get_stub_mode() != MODE_Os);
+}
+
+static void write_proc_func_header( FILE *file, int indent, const type_t *iface,
+                                    const var_t *func, unsigned int *offset,
+                                    unsigned short num_proc )
+{
+    var_t *var;
+    var_list_t *args = type_get_function_args( func->type );
+    unsigned char explicit_fc, implicit_fc;
+    unsigned char handle_flags;
+    const var_t *handle_var = get_func_handle_var( iface, func, &explicit_fc, &implicit_fc );
+    unsigned char oi_flags = RPC_FC_PROC_OIF_RPCFLAGS | RPC_FC_PROC_OIF_NEWINIT;
+    unsigned int rpc_flags = get_rpc_flags( func->attrs );
+    unsigned int nb_args = 0;
+    unsigned int stack_size = 0;
+    unsigned short param_num = 0;
+    unsigned short handle_stack_offset = 0;
+    unsigned short handle_param_num = 0;
+
+    if (is_full_pointer_function( func )) oi_flags |= RPC_FC_PROC_OIF_FULLPTR;
+    if (is_object( iface ))
+    {
+        oi_flags |= RPC_FC_PROC_OIF_OBJECT;
+        if (get_stub_mode() == MODE_Oif) oi_flags |= RPC_FC_PROC_OIF_OBJ_V2;
+        stack_size += pointer_size;
+    }
+
+    if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
+    {
+        if (var == handle_var)
+        {
+            handle_stack_offset = stack_size;
+            handle_param_num = param_num;
+        }
+        stack_size += get_stack_size( var->type, var->attrs, NULL );
+        param_num++;
+        nb_args++;
+    }
+    if (!is_void( type_function_get_rettype( func->type )))
+    {
+        stack_size += pointer_size;
+        nb_args++;
+    }
+
+    print_file( file, 0, "/* %u (procedure %s::%s) */\n", *offset, iface->name, func->name );
+    print_file( file, indent, "0x%02x,\t/* %s */\n", implicit_fc,
+                implicit_fc ? string_of_type(implicit_fc) : "explicit handle" );
+    print_file( file, indent, "0x%02x,\n", oi_flags );
+    print_file( file, indent, "NdrFcLong(0x%x),\n", rpc_flags );
+    print_file( file, indent, "NdrFcShort(0x%hx),\t/* method %hu */\n", num_proc, num_proc );
+    print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack size = %hu */\n", stack_size, stack_size );
+    *offset += 10;
+
+    if (!implicit_fc)
+    {
+        switch (explicit_fc)
+        {
+        case RPC_FC_BIND_PRIMITIVE:
+            handle_flags = 0;
+            print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
+            print_file( file, indent, "0x%02x,\n", handle_flags );
+            print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
+                        handle_stack_offset, handle_stack_offset );
+            *offset += 4;
+            break;
+        case RPC_FC_BIND_GENERIC:
+            handle_flags = type_memsize( handle_var->type );
+            print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
+            print_file( file, indent, "0x%02x,\n", handle_flags );
+            print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
+                        handle_stack_offset, handle_stack_offset );
+            print_file( file, indent, "0x%02x,\n", get_generic_handle_offset( handle_var->type ) );
+            print_file( file, indent, "0x%x,\t/* FC_PAD */\n", RPC_FC_PAD);
+            *offset += 6;
+            break;
+        case RPC_FC_BIND_CONTEXT:
+            handle_flags = get_contexthandle_flags( iface, handle_var->attrs, handle_var->type );
+            print_file( file, indent, "0x%02x,\t/* %s */\n", explicit_fc, string_of_type(explicit_fc) );
+            print_file( file, indent, "0x%02x,\n", handle_flags );
+            print_file( file, indent, "NdrFcShort(0x%hx),\t/* stack offset = %hu */\n",
+                        handle_stack_offset, handle_stack_offset );
+            print_file( file, indent, "0x%02x,\n", get_context_handle_offset( handle_var->type ) );
+            print_file( file, indent, "0x%02x,\t/* param %hu */\n", handle_param_num, handle_param_num );
+            *offset += 6;
+            break;
+        }
+    }
+
+    if (get_stub_mode() == MODE_Oif)
+    {
+        unsigned char oi2_flags = get_func_oi2_flags( func );
+        unsigned char ext_flags = 0;
+        unsigned int size;
+
+        if (is_attr( func->attrs, ATTR_NOTIFY )) ext_flags |= 0x08;  /* HasNotify */
+        if (is_attr( func->attrs, ATTR_NOTIFYFLAG )) ext_flags |= 0x10;  /* HasNotify2 */
+
+        size = get_function_buffer_size( func, PASS_IN );
+        print_file( file, indent, "NdrFcShort(0x%x),\t/* client buffer = %hu */\n", size, size );
+        size = get_function_buffer_size( func, PASS_OUT );
+        print_file( file, indent, "NdrFcShort(0x%x),\t/* server buffer = %hu */\n", size, size );
+        print_file( file, indent, "0x%02x,\n", oi2_flags );
+        print_file( file, indent, "0x%02x,\t/* %u params */\n", nb_args, nb_args );
+        print_file( file, indent, "0x%02x,\n", pointer_size == 8 ? 10 : 8 );
+        print_file( file, indent, "0x%02x,\n", ext_flags );
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* server corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* client corr hint */
+        print_file( file, indent, "NdrFcShort(0x0),\n" );  /* FIXME: notify index */
+        *offset += 14;
+        if (pointer_size == 8)
+        {
+            unsigned short pos = 0, fpu_mask = 0;
+
+            if (is_object( iface )) pos += 2;
+            if (args) LIST_FOR_EACH_ENTRY( var, args, var_t, entry )
+            {
+                if (type_get_type( var->type ) == TYPE_BASIC)
+                {
+                    switch (type_basic_get_type( var->type ))
+                    {
+                    case TYPE_BASIC_FLOAT:  fpu_mask |= 1 << pos; break;
+                    case TYPE_BASIC_DOUBLE: fpu_mask |= 2 << pos; break;
+                    default: break;
+                    }
+                }
+                pos += 2;
+                if (pos >= 16) break;
+            }
+            print_file( file, indent, "NdrFcShort(0x%x),\n", fpu_mask );  /* floating point mask */
+            *offset += 2;
+        }
+    }
+}
+
+static void write_procformatstring_func( FILE *file, int indent, const type_t *iface,
+                                         const var_t *func, unsigned int *offset,
+                                         unsigned short num_proc )
 {
+    unsigned int stack_offset = is_object( iface ) ? pointer_size : 0;
+    int is_interpreted = is_interpreted_func( iface, func );
+    int is_new_style = is_interpreted && (get_stub_mode() == MODE_Oif);
+
+    if (is_interpreted) write_proc_func_header( file, indent, iface, func, offset, num_proc );
+
     /* emit argument data */
     if (type_get_function_args(func->type))
     {
@@ -889,22 +1435,35 @@ static void write_procformatstring_func( FILE *file, int indent,
         LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
         {
             print_file( file, 0, "/* %u (parameter %s) */\n", *offset, var->name );
-            *offset += write_procformatstring_type(file, indent, var->type, var->attrs, FALSE);
+            if (is_new_style)
+                *offset += write_new_procformatstring_type(file, indent, var->type, var->attrs,
+                                                           FALSE, &stack_offset);
+            else
+                *offset += write_old_procformatstring_type(file, indent, var->type, var->attrs,
+                                                           FALSE, is_interpreted);
         }
     }
 
     /* emit return value data */
     if (is_void(type_function_get_rettype(func->type)))
     {
-        print_file(file, 0, "/* %u (void) */\n", *offset);
-        print_file(file, indent, "0x5b,    /* FC_END */\n");
-        print_file(file, indent, "0x5c,    /* FC_PAD */\n");
-        *offset += 2;
+        if (!is_new_style)
+        {
+            print_file(file, 0, "/* %u (void) */\n", *offset);
+            print_file(file, indent, "0x5b,    /* FC_END */\n");
+            print_file(file, indent, "0x5c,    /* FC_PAD */\n");
+            *offset += 2;
+        }
     }
     else
     {
         print_file( file, 0, "/* %u (return value) */\n", *offset );
-        *offset += write_procformatstring_type(file, indent, type_function_get_rettype(func->type), NULL, TRUE);
+        if (is_new_style)
+            *offset += write_new_procformatstring_type(file, indent, type_function_get_rettype(func->type),
+                                                       NULL, TRUE, &stack_offset);
+        else
+            *offset += write_old_procformatstring_type(file, indent, type_function_get_rettype(func->type),
+                                                       NULL, TRUE, is_interpreted);
     }
 }
 
@@ -917,13 +1476,16 @@ static void write_procformatstring_stmts(FILE *file, int indent, const statement
         if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE)
         {
             const statement_t *stmt_func;
-            if (!pred(stmt->u.type))
-                continue;
-            STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(stmt->u.type))
+            const type_t *iface = stmt->u.type;
+            const type_t *parent = type_iface_get_inherit( iface );
+            int count = parent ? count_methods( parent ) : 0;
+
+            if (!pred(iface)) continue;
+            STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
             {
-                const var_t *func = stmt_func->u.var;
+                var_t *func = stmt_func->u.var;
                 if (is_local(func->attrs)) continue;
-                write_procformatstring_func( file, indent, func, offset );
+                write_procformatstring_func( file, indent, iface, func, offset, count++ );
             }
         }
         else if (stmt->type == STMT_LIBRARY)
@@ -972,47 +1534,33 @@ void write_procformatstring_offsets( FILE *file, const type_t *iface )
     print_file( file, indent,  "};\n\n" );
 }
 
-static int write_base_type(FILE *file, const type_t *type, int convert_to_signed_type, unsigned int *typestring_offset)
+static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
 {
     unsigned char fc;
 
     if (type_get_type(type) == TYPE_BASIC)
-        fc = get_basic_fc(type);
+        fc = get_basic_fc_signed(type);
     else if (type_get_type(type) == TYPE_ENUM)
         fc = get_enum_fc(type);
     else
         return 0;
 
-    if (convert_to_signed_type)
-    {
-        switch(fc)
-        {
-        case RPC_FC_USMALL:
-            fc = RPC_FC_SMALL;
-            break;
-        case RPC_FC_USHORT:
-            fc = RPC_FC_SHORT;
-            break;
-        case RPC_FC_ULONG:
-            fc = RPC_FC_LONG;
-            break;
-        }
-    }
-
     print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
     *typestring_offset += 1;
     return 1;
 }
 
 /* write conformance / variance descriptor */
-static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
+static unsigned int write_conf_or_var_desc(FILE *file, const type_t *cont_type,
                                            unsigned int baseoff, const type_t *type,
                                            const expr_t *expr)
 {
     unsigned char operator_type = 0;
     unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
-    const char *conftype_string = "";
+    const char *conftype_string = "field";
     const expr_t *subexpr;
+    const type_t *iface = NULL;
+    const char *name;
 
     if (!expr)
     {
@@ -1035,20 +1583,22 @@ static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
         return 4;
     }
 
-    if (!structure)
+    if (!cont_type)  /* top-level conformance */
     {
-        /* Top-level conformance calculations are done inline.  */
-        print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n",
-                    RPC_FC_TOP_LEVEL_CONFORMANCE);
-        print_file (file, 2, "0x0,\n");
-        print_file (file, 2, "NdrFcShort(0x0),\n");
-        return 4;
+        conftype = RPC_FC_TOP_LEVEL_CONFORMANCE;
+        conftype_string = "parameter";
+        cont_type = current_func->type;
+        name = current_func->name;
+        iface = current_iface;
     }
-
-    if (is_ptr(type) || (is_array(type) && type_array_is_decl_as_ptr(type)))
+    else
     {
-        conftype = RPC_FC_POINTER_CONFORMANCE;
-        conftype_string = "field pointer, ";
+        name = cont_type->name;
+        if (is_ptr(type) || (is_array(type) && type_array_is_decl_as_ptr(type)))
+        {
+            conftype = RPC_FC_POINTER_CONFORMANCE;
+            conftype_string = "field pointer";
+        }
     }
 
     subexpr = expr;
@@ -1096,23 +1646,45 @@ static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
         unsigned char param_type = 0;
         unsigned int offset = 0;
         const var_t *var;
-        var_list_t *fields = type_struct_get_fields(structure);
+        struct expr_loc expr_loc;
 
-        if (fields) LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
+        if (type_get_type(cont_type) == TYPE_FUNCTION)
         {
-            unsigned int size = field_memsize( var->type, &offset );
-            if (var->name && !strcmp(var->name, subexpr->u.sval))
+            var_list_t *args = type_get_function_args( cont_type );
+
+            if (is_object( iface )) offset += pointer_size;
+            if (args) LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
             {
-                correlation_variable = var->type;
-                break;
+                if (var->name && !strcmp(var->name, subexpr->u.sval))
+                {
+                    expr_loc.v = var;
+                    correlation_variable = var->type;
+                    break;
+                }
+                offset += get_stack_size( var->type, var->attrs, NULL );
             }
-            offset += size;
         }
-        if (!correlation_variable)
-            error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
-                  subexpr->u.sval);
+        else
+        {
+            var_list_t *fields = type_struct_get_fields( cont_type );
 
-        correlation_variable = expr_resolve_type(NULL, structure, expr);
+            if (fields) LIST_FOR_EACH_ENTRY( var, fields, const var_t, entry )
+            {
+                unsigned int size = field_memsize( var->type, &offset );
+                if (var->name && !strcmp(var->name, subexpr->u.sval))
+                {
+                    expr_loc.v = var;
+                    correlation_variable = var->type;
+                    break;
+                }
+                offset += size;
+            }
+        }
+
+        if (!correlation_variable)
+            error("write_conf_or_var_desc: couldn't find variable %s in %s\n", subexpr->u.sval, name);
+        expr_loc.attr = NULL;
+        correlation_variable = expr_resolve_type(&expr_loc, cont_type, expr);
 
         offset -= baseoff;
 
@@ -1167,14 +1739,14 @@ static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
             return 0;
         }
 
-        print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
-                   conftype | param_type, conftype_string, string_of_type(param_type));
-        print_file(file, 2, "0x%x, /* %s */\n", operator_type,
+        print_file(file, 2, "0x%x,\t/* Corr desc: %s %s, %s */\n",
+                   conftype | param_type, conftype_string, subexpr->u.sval, string_of_type(param_type));
+        print_file(file, 2, "0x%x,\t/* %s */\n", operator_type,
                    operator_type ? string_of_type(operator_type) : "no operators");
         print_file(file, 2, "NdrFcShort(0x%hx),\t/* offset = %d */\n",
                    (unsigned short)offset, offset);
     }
-    else
+    else if (!iface || is_interpreted_func( iface, current_func ))
     {
         unsigned int callback_offset = 0;
         struct expr_eval_routine *eval;
@@ -1182,9 +1754,10 @@ static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
 
         LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
         {
-            if (eval->structure == structure ||
-                (eval->structure->name && structure->name &&
-                 !strcmp(eval->structure->name, structure->name) &&
+            if (eval->cont_type == cont_type ||
+                (type_get_type( eval->cont_type ) == type_get_type( cont_type ) &&
+                 eval->iface == iface &&
+                 eval->name && name && !strcmp(eval->name, name) &&
                  !compare_expr(eval->expr, expr)))
             {
                 found = 1;
@@ -1196,7 +1769,9 @@ static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
         if (!found)
         {
             eval = xmalloc (sizeof(*eval));
-            eval->structure = structure;
+            eval->iface = iface;
+            eval->cont_type = cont_type;
+            eval->name = xstrdup( name );
             eval->baseoff = baseoff;
             eval->expr = expr;
             list_add_tail (&expr_eval_routines, &eval->entry);
@@ -1205,10 +1780,16 @@ static unsigned int write_conf_or_var_desc(FILE *file, const type_t *structure,
         if (callback_offset > USHRT_MAX)
             error("Maximum number of callback routines reached\n");
 
-        print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string);
-        print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
+        print_file(file, 2, "0x%x,\t/* Corr desc: %s in %s */\n", conftype, conftype_string, name);
+        print_file(file, 2, "0x%x,\t/* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
         print_file(file, 2, "NdrFcShort(0x%hx),\t/* %u */\n", (unsigned short)callback_offset, callback_offset);
     }
+    else  /* output a dummy corr desc that isn't used */
+    {
+        print_file(file, 2, "0x%x,\t/* Corr desc: unused for %s */\n", conftype, name);
+        print_file(file, 2, "0x0,\n" );
+        print_file(file, 2, "NdrFcShort(0x0),\n" );
+    }
     return 4;
 }
 
@@ -1301,6 +1882,7 @@ static unsigned int type_memsize_and_alignment(const type_t *t, unsigned int *al
             break;
         case RPC_FC_INT3264:
         case RPC_FC_UINT3264:
+        case RPC_FC_BIND_PRIMITIVE:
             assert( pointer_size );
             size = pointer_size;
             if (size > *align) *align = size;
@@ -1501,7 +2083,7 @@ void write_full_pointer_free(FILE *file, int indent, const var_t *func)
 
 static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs,
                                             const type_t *type,
-                                            int toplevel_param,
+                                            enum type_context context,
                                             unsigned int offset,
                                             unsigned int *typeformat_offset)
 {
@@ -1511,7 +2093,7 @@ static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs
     int pointer_type;
     unsigned char flags = 0;
 
-    pointer_type = get_pointer_fc(type, attrs, toplevel_param);
+    pointer_type = get_pointer_fc_context(type, attrs, context);
 
     in_attr = is_attr(attrs, ATTR_IN);
     out_attr = is_attr(attrs, ATTR_OUT);
@@ -1520,8 +2102,12 @@ static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs
     if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
         flags |= RPC_FC_P_ONSTACK;
 
-    if (is_ptr(type) && is_declptr(type_pointer_get_ref(type)))
-        flags |= RPC_FC_P_DEREF;
+    if (is_ptr(type))
+    {
+        type_t *ref = type_pointer_get_ref(type);
+        if(is_declptr(ref) && !is_user_type(ref))
+            flags |= RPC_FC_P_DEREF;
+    }
 
     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
                pointer_type,
@@ -1542,7 +2128,8 @@ static unsigned int write_nonsimple_pointer(FILE *file, const attr_list_t *attrs
     return start_offset;
 }
 
-static unsigned int write_simple_pointer(FILE *file, const attr_list_t *attrs, const type_t *type, int toplevel_param)
+static unsigned int write_simple_pointer(FILE *file, const attr_list_t *attrs,
+                                         const type_t *type, enum type_context context)
 {
     unsigned char fc;
     unsigned char pointer_fc;
@@ -1556,7 +2143,7 @@ static unsigned int write_simple_pointer(FILE *file, const attr_list_t *attrs, c
     if (is_string_type(attrs, type))
         error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
 
-    pointer_fc = get_pointer_fc(type, attrs, toplevel_param);
+    pointer_fc = get_pointer_fc_context(type, attrs, context);
 
     ref = type_pointer_get_ref(type);
     if (type_get_type(ref) == TYPE_ENUM)
@@ -1584,7 +2171,7 @@ static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
 
 static unsigned int write_pointer_tfs(FILE *file, const attr_list_t *attrs,
                                       type_t *type, unsigned int ref_offset,
-                                      int toplevel_param,
+                                      enum type_context context,
                                       unsigned int *typestring_offset)
 {
     unsigned int offset = *typestring_offset;
@@ -1597,15 +2184,11 @@ static unsigned int write_pointer_tfs(FILE *file, const attr_list_t *attrs,
     {
     case TGT_BASIC:
     case TGT_ENUM:
-        *typestring_offset += write_simple_pointer(file, attrs, type,
-                                                   toplevel_param);
+        *typestring_offset += write_simple_pointer(file, attrs, type, context);
         break;
     default:
         if (ref_offset)
-            write_nonsimple_pointer(file, attrs, type,
-                                    toplevel_param,
-                                    ref_offset,
-                                    typestring_offset);
+            write_nonsimple_pointer(file, attrs, type, context, ref_offset, typestring_offset);
         break;
     }
 
@@ -1637,7 +2220,7 @@ static int user_type_has_variable_size(const type_t *t)
     return FALSE;
 }
 
-static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
+static unsigned int write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
 {
     unsigned int start, absoff, flags;
     const char *name = NULL;
@@ -1648,6 +2231,8 @@ static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
     unsigned short funoff = user_type_offset(name);
     short reloff;
 
+    if (processed(type)) return type->typestring_offset;
+
     guard_rec(type);
 
     if(user_type_has_variable_size(utype)) usize = 0;
@@ -1695,6 +2280,7 @@ static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
     reloff = absoff - *tfsoff;
     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n", reloff, reloff, absoff);
     *tfsoff += 2;
+    return start;
 }
 
 static void write_member_type(FILE *file, const type_t *cont,
@@ -1733,7 +2319,7 @@ static void write_member_type(FILE *file, const type_t *cont,
         print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
         *tfsoff += 1;
     }
-    else if (!write_base_type(file, type, TRUE, tfsoff))
+    else if (!write_base_type(file, type, tfsoff))
         error("Unsupported member type %d\n", type_get_type(type));
 }
 
@@ -1748,13 +2334,14 @@ static void write_array_element_type(FILE *file, const type_t *type,
 
         if (processed(ref))
         {
-            write_nonsimple_pointer(file, NULL, elem, FALSE, ref->typestring_offset, tfsoff);
+            write_nonsimple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER,
+                                    ref->typestring_offset, tfsoff);
             return;
         }
         if (!is_string_type(NULL, elem) &&
             (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM))
         {
-            *tfsoff += write_simple_pointer(file, NULL, elem, FALSE);
+            *tfsoff += write_simple_pointer(file, NULL, elem, TYPE_CONTEXT_CONTAINER);
             return;
         }
     }
@@ -1837,11 +2424,12 @@ static int write_pointer_description_offsets(
             type_t *ref = type_pointer_get_ref(type);
 
             if (is_string_type(attrs, type))
-                write_string_tfs(file, attrs, type, FALSE, NULL, typestring_offset);
+                write_string_tfs(file, attrs, type, TYPE_CONTEXT_CONTAINER, NULL, typestring_offset);
             else if (processed(ref))
-                write_nonsimple_pointer(file, attrs, type, FALSE, ref->typestring_offset, typestring_offset);
+                write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER,
+                                        ref->typestring_offset, typestring_offset);
             else if (type_get_type(ref) == TYPE_BASIC || type_get_type(ref) == TYPE_ENUM)
-                *typestring_offset += write_simple_pointer(file, attrs, type, FALSE);
+                *typestring_offset += write_simple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER);
             else
                 error("write_pointer_description_offsets: type format string unknown\n");
         }
@@ -1852,7 +2440,7 @@ static int write_pointer_description_offsets(
              * pointer has to be written in-place here */
             if (is_string_type(attrs, type))
                 offset += 4;
-            write_nonsimple_pointer(file, attrs, type, FALSE, offset, typestring_offset);
+            write_nonsimple_pointer(file, attrs, type, TYPE_CONTEXT_CONTAINER, offset, typestring_offset);
         }
 
         return 1;
@@ -2194,20 +2782,20 @@ int is_declptr(const type_t *t)
 }
 
 static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
-                                     type_t *type, int toplevel_param,
+                                     type_t *type, enum type_context context,
                                      const char *name, unsigned int *typestring_offset)
 {
     unsigned int start_offset;
     unsigned char rtype;
     type_t *elem_type;
+    int is_processed = processed(type);
 
     start_offset = *typestring_offset;
-    update_tfsoff(type, start_offset, file);
 
     if (is_declptr(type))
     {
         unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
-        int pointer_type = get_pointer_fc(type, attrs, toplevel_param);
+        int pointer_type = get_pointer_fc_context(type, attrs, context);
         if (!pointer_type)
             pointer_type = RPC_FC_RP;
         print_start_tfs_comment(file, type, *typestring_offset);
@@ -2220,6 +2808,7 @@ static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
             print_file(file, 2, "NdrFcShort(0x2),\n");
             *typestring_offset += 2;
         }
+        is_processed = FALSE;
     }
 
     if (is_array(type))
@@ -2244,6 +2833,8 @@ static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
     {
         unsigned int dim = type_array_get_dim(type);
 
+        if (is_processed) return start_offset;
+
         /* FIXME: multi-dimensional array */
         if (0xffffu < dim)
             error("array size for parameter %s exceeds %u bytes by %u bytes\n",
@@ -2259,6 +2850,7 @@ static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
         print_file(file, 2, "NdrFcShort(0x%hx),\t/* %d */\n", (unsigned short)dim, dim);
         *typestring_offset += 2;
 
+        update_tfsoff(type, start_offset, file);
         return start_offset;
     }
     else if (is_conformant_array(type))
@@ -2277,10 +2869,13 @@ static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
              : 0),
             type, type_array_get_conformance(type));
 
+        update_tfsoff(type, start_offset, file);
         return start_offset;
     }
     else
     {
+        if (is_processed) return start_offset;
+
         if (rtype == RPC_FC_WCHAR)
             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
         else
@@ -2288,6 +2883,7 @@ static unsigned int write_string_tfs(FILE *file, const attr_list_t *attrs,
         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
         *typestring_offset += 2;
 
+        update_tfsoff(type, start_offset, file);
         return start_offset;
     }
 }
@@ -2493,6 +3089,8 @@ static unsigned int write_struct_tfs(FILE *file, type_t *type,
     unsigned char fc = get_struct_fc(type);
     var_list_t *fields = type_struct_get_fields(type);
 
+    if (processed(type)) return type->typestring_offset;
+
     guard_rec(type);
     current_structure = type;
 
@@ -2509,7 +3107,7 @@ static unsigned int write_struct_tfs(FILE *file, type_t *type,
     if (array && !processed(array->type))
     {
         if(is_string_type(array->attrs, array->type))
-            write_string_tfs(file, array->attrs, array->type, FALSE, array->name, tfsoff);
+            write_string_tfs(file, array->attrs, array->type, TYPE_CONTEXT_CONTAINER, array->name, tfsoff);
         else
             write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
     }
@@ -2578,11 +3176,11 @@ static unsigned int write_struct_tfs(FILE *file, type_t *type,
             {
             case TGT_POINTER:
                 if (is_string_type(f->attrs, ft))
-                    write_string_tfs(file, f->attrs, ft, FALSE, f->name, tfsoff);
+                    write_string_tfs(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, f->name, tfsoff);
                 else
                     write_pointer_tfs(file, f->attrs, ft,
                                       type_pointer_get_ref(ft)->typestring_offset,
-                                      FALSE, tfsoff);
+                                      TYPE_CONTEXT_CONTAINER, tfsoff);
                 break;
             case TGT_ARRAY:
                 if (type_array_is_decl_as_ptr(ft))
@@ -2596,7 +3194,7 @@ static unsigned int write_struct_tfs(FILE *file, type_t *type,
                      * pointer has to be written in-place here */
                     if (is_string_type(f->attrs, ft))
                         offset += 4;
-                    write_nonsimple_pointer(file, f->attrs, ft, FALSE, offset, tfsoff);
+                    write_nonsimple_pointer(file, f->attrs, ft, TYPE_CONTEXT_CONTAINER, offset, tfsoff);
                 }
                 break;
             default:
@@ -2642,7 +3240,8 @@ static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
     *tfsoff += 2;
 }
 
-static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
+static unsigned int write_union_tfs(FILE *file, const attr_list_t *attrs,
+                                    type_t *type, unsigned int *tfsoff)
 {
     unsigned int start_offset;
     unsigned int size;
@@ -2652,6 +3251,10 @@ static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfso
     short nodeftype = 0xffff;
     var_t *f;
 
+    if (processed(type) &&
+        (type_get_type(type) == TYPE_ENCAPSULATED_UNION || !is_attr(type->attrs, ATTR_SWITCHTYPE)))
+        return type->typestring_offset;
+
     guard_rec(type);
 
     size = type_memsize(type);
@@ -2678,7 +3281,8 @@ static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfso
 
         if (type_get_type(st) == TYPE_BASIC)
         {
-            switch (get_basic_fc(st))
+            fc = get_basic_fc(st);
+            switch (fc)
             {
             case RPC_FC_CHAR:
             case RPC_FC_SMALL:
@@ -2689,7 +3293,6 @@ static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfso
             case RPC_FC_USHORT:
             case RPC_FC_LONG:
             case RPC_FC_ULONG:
-                fc = get_basic_fc(st);
                 break;
             default:
                 fc = 0;
@@ -2708,13 +3311,14 @@ static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfso
     }
     else if (is_attr(type->attrs, ATTR_SWITCHTYPE))
     {
-        static const expr_t dummy_expr;  /* FIXME */
+        const expr_t *switch_is = get_attrp(attrs, ATTR_SWITCHIS);
         const type_t *st = get_attrp(type->attrs, ATTR_SWITCHTYPE);
         unsigned char fc;
 
         if (type_get_type(st) == TYPE_BASIC)
         {
-            switch (get_basic_fc(st))
+            fc = get_basic_fc(st);
+            switch (fc)
             {
             case RPC_FC_CHAR:
             case RPC_FC_SMALL:
@@ -2725,7 +3329,6 @@ static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfso
             case RPC_FC_ULONG:
             case RPC_FC_ENUM16:
             case RPC_FC_ENUM32:
-                fc = get_basic_fc(st);
                 break;
             default:
                 fc = 0;
@@ -2741,8 +3344,7 @@ static unsigned int write_union_tfs(FILE *file, type_t *type, unsigned int *tfso
         print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
                    fc, string_of_type(fc));
         *tfsoff += 2;
-
-        *tfsoff += write_conf_or_var_desc(file, NULL, *tfsoff, st, &dummy_expr );
+        *tfsoff += write_conf_or_var_desc(file, current_structure, 0, st, switch_is );
         print_file(file, 2, "NdrFcShort(0x2),\t/* Offset= 2 (%u) */\n", *tfsoff + 2);
         *tfsoff += 2;
         print_file(file, 0, "/* %u */\n", *tfsoff);
@@ -2802,7 +3404,10 @@ static unsigned int write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *t
     unsigned int start_offset = *typeformat_offset;
     expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
 
+    if (!iid && processed(type)) return type->typestring_offset;
+
     print_start_tfs_comment(file, type, start_offset);
+    update_tfsoff(type, start_offset, file);
 
     if (iid)
     {
@@ -2819,7 +3424,6 @@ static unsigned int write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *t
         if (! uuid)
             error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
 
-        update_tfsoff(type, start_offset, file);
         print_file(file, 2, "0x2f,\t/* FC_IP */\n");
         print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
         print_file(file, 2, "NdrFcLong(0x%08x),\n", uuid->Data1);
@@ -2838,27 +3442,26 @@ static unsigned int write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *t
 
 static unsigned int write_contexthandle_tfs(FILE *file,
                                             const attr_list_t *attrs,
-                                            const type_t *type,
+                                            type_t *type,
+                                            int toplevel_param,
                                             unsigned int *typeformat_offset)
 {
     unsigned int start_offset = *typeformat_offset;
-    unsigned char flags = 0;
+    unsigned char flags = get_contexthandle_flags( current_iface, attrs, type );
 
-    if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
-        flags |= NDR_STRICT_CONTEXT_HANDLE;
+    print_start_tfs_comment(file, type, start_offset);
 
-    if (is_ptr(type))
-        flags |= 0x80;
-    if (is_attr(attrs, ATTR_IN))
+    if (flags & 0x80)  /* via ptr */
     {
-        flags |= 0x40;
-        if (!is_attr(attrs, ATTR_OUT))
-            flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
+        int pointer_type = get_pointer_fc( type, attrs, toplevel_param );
+        if (!pointer_type) pointer_type = RPC_FC_RP;
+        *typeformat_offset += 4;
+        print_file(file, 2,"0x%x, 0x0,\t/* %s */\n", pointer_type, string_of_type(pointer_type) );
+        print_file(file, 2, "NdrFcShort(0x2),\t /* Offset= 2 (%u) */\n", *typeformat_offset);
+        print_file(file, 0, "/* %2u */\n", *typeformat_offset);
     }
-    if (is_attr(attrs, ATTR_OUT))
-        flags |= 0x20;
 
-    WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
+    print_file(file, 2, "0x%02x,\t/* FC_BIND_CONTEXT */\n", RPC_FC_BIND_CONTEXT);
     print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
     /* return and can't be null values overlap */
     if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
@@ -2878,10 +3481,11 @@ static unsigned int write_contexthandle_tfs(FILE *file,
     if (flags & 0x80)
         print_file(file, 0, "via ptr, ");
     print_file(file, 0, "*/\n");
-    print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
+    print_file(file, 2, "0x%x,\t/* rundown routine */\n", get_context_handle_offset( type ));
     print_file(file, 2, "0, /* FIXME: param num */\n");
     *typeformat_offset += 4;
 
+    update_tfsoff( type, start_offset, file );
     return start_offset;
 }
 
@@ -2907,6 +3511,7 @@ static unsigned int write_range_tfs(FILE *file, const attr_list_t *attrs,
     print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
     print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", range_min->cval, range_min->cval);
     print_file(file, 2, "NdrFcLong(0x%x),\t/* %u */\n", range_max->cval, range_max->cval);
+    update_tfsoff( type, start_offset, file );
     *typeformat_offset += 10;
 
     return start_offset;
@@ -2924,14 +3529,12 @@ static unsigned int write_type_tfs(FILE *file, int indent,
     {
     case TGT_CTXT_HANDLE:
     case TGT_CTXT_HANDLE_POINTER:
-        return write_contexthandle_tfs(file, attrs, type, typeformat_offset);
+        return write_contexthandle_tfs(file, attrs, type,
+                                       context == TYPE_CONTEXT_TOPLEVELPARAM, typeformat_offset);
     case TGT_USER_TYPE:
-        write_user_tfs(file, type, typeformat_offset);
-        return type->typestring_offset;
+        return write_user_tfs(file, type, typeformat_offset);
     case TGT_STRING:
-        return write_string_tfs(file, attrs, type,
-                                context == TYPE_CONTEXT_TOPLEVELPARAM,
-                                name, typeformat_offset);
+        return write_string_tfs(file, attrs, type, context, name, typeformat_offset);
     case TGT_ARRAY:
     {
         unsigned int off;
@@ -2948,7 +3551,7 @@ static unsigned int write_type_tfs(FILE *file, int indent,
             int ptr_type;
             ptr_type = get_pointer_fc(type, attrs,
                                       context == TYPE_CONTEXT_TOPLEVELPARAM);
-            if (ptr_type != RPC_FC_RP)
+            if (ptr_type != RPC_FC_RP || type_array_is_decl_as_ptr(type))
             {
                 unsigned int absoff = type->typestring_offset;
                 short reloff = absoff - (*typeformat_offset + 2);
@@ -2958,17 +3561,17 @@ static unsigned int write_type_tfs(FILE *file, int indent,
                            string_of_type(ptr_type));
                 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
                            reloff, reloff, absoff);
+                if (ptr_type != RPC_FC_RP) update_tfsoff( type, off, file );
                 *typeformat_offset += 4;
             }
+            type->details.array.ptr_tfsoff = off;
         }
         return off;
     }
     case TGT_STRUCT:
-        if (processed(type)) return type->typestring_offset;
         return write_struct_tfs(file, type, name, typeformat_offset);
     case TGT_UNION:
-        if (processed(type)) return type->typestring_offset;
-        return write_union_tfs(file, type, typeformat_offset);
+        return write_union_tfs(file, attrs, type, typeformat_offset);
     case TGT_ENUM:
     case TGT_BASIC:
         /* nothing to do */
@@ -2983,27 +3586,20 @@ static unsigned int write_type_tfs(FILE *file, int indent,
     case TGT_IFACE_POINTER:
         return write_ip_tfs(file, attrs, type, typeformat_offset);
     case TGT_POINTER:
-        if (processed(type_pointer_get_ref(type)))
-            offset = type_pointer_get_ref(type)->typestring_offset;
+    {
+        enum type_context ref_context;
+        if (context == TYPE_CONTEXT_TOPLEVELPARAM)
+            ref_context = TYPE_CONTEXT_PARAM;
+        else if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
+            ref_context = TYPE_CONTEXT_CONTAINER;
         else
-        {
-            enum type_context ref_context;
-            if (context == TYPE_CONTEXT_TOPLEVELPARAM)
-                ref_context = TYPE_CONTEXT_PARAM;
-            else if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
-                ref_context = TYPE_CONTEXT_CONTAINER;
-            else
-                ref_context = context;
-            offset = write_type_tfs(
-                file, indent, attrs, type_pointer_get_ref(type), name,
-                ref_context, typeformat_offset);
-        }
+            ref_context = context;
+        offset = write_type_tfs( file, indent, attrs, type_pointer_get_ref(type), name,
+                                 ref_context, typeformat_offset);
         if (context == TYPE_CONTEXT_CONTAINER_NO_POINTERS)
             return 0;
-        else
-            return write_pointer_tfs(file, attrs, type, offset,
-                                     context == TYPE_CONTEXT_TOPLEVELPARAM,
-                                     typeformat_offset);
+        return write_pointer_tfs(file, attrs, type, offset, context, typeformat_offset);
+    }
     case TGT_INVALID:
         break;
     }
@@ -3044,28 +3640,19 @@ static unsigned int process_tfs_stmts(FILE *file, const statement_list_t *stmts,
         STATEMENTS_FOR_EACH_FUNC( stmt_func, type_iface_get_stmts(iface) )
         {
             const var_t *func = stmt_func->u.var;
-                if (is_local(func->attrs)) continue;
+            current_func = func;
+            if (is_local(func->attrs)) continue;
 
-                if (!is_void(type_function_get_rettype(func->type)))
-                {
-                    update_tfsoff(type_function_get_rettype(func->type),
-                                  write_type_tfs(
-                                      file, 2, func->attrs,
-                                      type_function_get_rettype(func->type),
-                                      func->name, TYPE_CONTEXT_PARAM,
-                                      typeformat_offset),
-                                  file);
-                }
+            if (!is_void(type_function_get_rettype(func->type)))
+            {
+                write_type_tfs( file, 2, func->attrs, type_function_get_rettype(func->type),
+                                func->name, TYPE_CONTEXT_PARAM, typeformat_offset);
+            }
 
-                if (type_get_function_args(func->type))
-                    LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
-                        update_tfsoff(
-                            var->type,
-                            write_type_tfs(
-                                file, 2, var->attrs, var->type, var->name,
-                                TYPE_CONTEXT_TOPLEVELPARAM,
-                                typeformat_offset),
-                            file);
+            if (type_get_function_args(func->type))
+                LIST_FOR_EACH_ENTRY( var, type_get_function_args(func->type), const var_t, entry )
+                    write_type_tfs( file, 2, var->attrs, var->type, var->name,
+                                    TYPE_CONTEXT_TOPLEVELPARAM, typeformat_offset );
         }
     }
 
@@ -3107,7 +3694,7 @@ static unsigned int get_required_buffer_size_type(
     const type_t *type, const char *name, const attr_list_t *attrs, int toplevel_param, unsigned int *alignment)
 {
     *alignment = 0;
-    switch (typegen_detect_type(type, NULL, TDT_IGNORE_STRINGS|TDT_IGNORE_RANGES))
+    switch (typegen_detect_type(type, NULL, TDT_IGNORE_RANGES))
     {
     case TGT_USER_TYPE:
     {
@@ -3181,38 +3768,33 @@ static unsigned int get_required_buffer_size_type(
         break;
 
     case TGT_POINTER:
-        if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_RP)
         {
+            unsigned int size, align;
             const type_t *ref = type_pointer_get_ref(type);
-            switch (typegen_detect_type(ref, NULL, TDT_ALL_TYPES))
+            if (is_string_type( attrs, ref )) break;
+            if (!(size = get_required_buffer_size_type( ref, name, NULL, FALSE, &align ))) break;
+            if (get_pointer_fc(type, attrs, toplevel_param) != RPC_FC_RP)
             {
-            case TGT_BASIC:
-            case TGT_ENUM:
-            case TGT_RANGE:
-                return get_required_buffer_size_type( ref, name, NULL, FALSE, alignment );
-            case TGT_STRUCT:
-                if (get_struct_fc(ref) == RPC_FC_STRUCT)
-                    return get_required_buffer_size_type( ref, name, NULL, FALSE, alignment );
-                break;
-            case TGT_USER_TYPE:
-            case TGT_CTXT_HANDLE:
-            case TGT_CTXT_HANDLE_POINTER:
-            case TGT_STRING:
-            case TGT_POINTER:
-            case TGT_ARRAY:
-            case TGT_IFACE_POINTER:
-            case TGT_UNION:
-            case TGT_INVALID:
-                break;
+                size += 4 + align;
+                align = 4;
             }
+            *alignment = align;
+            return size;
         }
-        break;
 
     case TGT_ARRAY:
         if (get_pointer_fc(type, attrs, toplevel_param) == RPC_FC_RP)
-            return type_array_get_dim(type) *
-                get_required_buffer_size_type(type_array_get_element(type), name,
-                                              NULL, FALSE, alignment);
+        {
+            switch (get_array_fc(type))
+            {
+            case RPC_FC_SMFARRAY:
+            case RPC_FC_LGFARRAY:
+                return type_array_get_dim(type) *
+                    get_required_buffer_size_type(type_array_get_element(type), name,
+                                                  NULL, FALSE, alignment);
+            }
+        }
+        break;
 
     default:
         break;
@@ -3453,8 +4035,8 @@ expr_t *get_size_is_expr(const type_t *t, const char *name)
     return x;
 }
 
-static void write_parameter_conf_or_var_exprs(FILE *file, int indent, const char *local_var_prefix,
-                                              enum remoting_phase phase, const var_t *var)
+void write_parameter_conf_or_var_exprs(FILE *file, int indent, const char *local_var_prefix,
+                                       enum remoting_phase phase, const var_t *var, int valid_variance)
 {
     const type_t *type = var->type;
     /* get fundamental type for the argument */
@@ -3475,9 +4057,14 @@ static void write_parameter_conf_or_var_exprs(FILE *file, int indent, const char
                 if (type_array_has_variance(type))
                 {
                     print_file(file, indent, "__frame->_StubMsg.Offset = 0;\n"); /* FIXME */
-                    print_file(file, indent, "__frame->_StubMsg.ActualCount = (ULONG_PTR)");
-                    write_expr(file, type_array_get_variance(type), 1, 1, NULL, NULL, local_var_prefix);
-                    fprintf(file, ";\n\n");
+                    if (valid_variance)
+                    {
+                        print_file(file, indent, "__frame->_StubMsg.ActualCount = (ULONG_PTR)");
+                        write_expr(file, type_array_get_variance(type), 1, 1, NULL, NULL, local_var_prefix);
+                        fprintf(file, ";\n\n");
+                    }
+                    else
+                        print_file(file, indent, "__frame->_StubMsg.ActualCount = __frame->_StubMsg.MaxCount;\n\n");
                 }
             }
             break;
@@ -3524,8 +4111,9 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
                                enum pass pass, enum remoting_phase phase, const var_t *var)
 {
     int in_attr, out_attr, pointer_type;
+    const char *type_str = NULL;
     const type_t *type = var->type;
-    unsigned int start_offset = type->typestring_offset;
+    unsigned int alignment, start_offset = type->typestring_offset;
 
     if (is_ptr(type) || is_array(type))
         pointer_type = get_pointer_fc(type, var->attrs, pass != PASS_RETURN);
@@ -3550,7 +4138,9 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
             break;
         }
 
-    write_parameter_conf_or_var_exprs(file, indent, local_var_prefix, phase, var);
+    if (phase == PHASE_BUFFERSIZE && get_required_buffer_size( var, &alignment, pass )) return;
+
+    write_parameter_conf_or_var_exprs(file, indent, local_var_prefix, phase, var, TRUE);
 
     switch (typegen_detect_type(type, var->attrs, TDT_ALL_TYPES))
     {
@@ -3604,19 +4194,18 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
         if (phase == PHASE_FREE || pass == PASS_RETURN ||
             pointer_type != RPC_FC_RP)
         {
-            if (pointer_type == RPC_FC_RP && phase == PHASE_FREE &&
+            /* strings returned are assumed to be global and hence don't
+             * need freeing */
+            if (is_declptr(type) && !(phase == PHASE_FREE && pass == PASS_RETURN))
+                print_phase_function(file, indent, "Pointer", local_var_prefix,
+                                     phase, var, start_offset);
+            else if (pointer_type == RPC_FC_RP && phase == PHASE_FREE &&
                 !in_attr && is_conformant_array(type))
             {
                 print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
                 indent++;
                 print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
             }
-            /* strings returned are assumed to be global and hence don't
-             * need freeing */
-            else if (is_declptr(type) &&
-                     !(phase == PHASE_FREE && pass == PASS_RETURN))
-                print_phase_function(file, indent, "Pointer", local_var_prefix,
-                                     phase, var, start_offset);
         }
         else
         {
@@ -3672,7 +4261,7 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
         }
 
         if (pointer_type != RPC_FC_RP) array_type = "Pointer";
-        print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
+
         if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
         {
             /* these are all unmarshalled by allocating memory */
@@ -3681,11 +4270,20 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
                 ((tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY) && in_attr) ||
                 (tc == RPC_FC_CARRAY && !in_attr))
             {
+                if (type_array_is_decl_as_ptr(type) && type->details.array.ptr_tfsoff)
+                {
+                    print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var,
+                                         type->details.array.ptr_tfsoff);
+                    break;
+                }
+                print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
                 print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
                 indent++;
                 print_file(file, indent, "__frame->_StubMsg.pfnFree(%s%s);\n", local_var_prefix, var->name);
+                break;
             }
         }
+        print_phase_function(file, indent, array_type, local_var_prefix, phase, var, start_offset);
         break;
     }
     case TGT_BASIC:
@@ -3771,8 +4369,6 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
                 print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
             break;
         case TGT_STRUCT:
-        {
-            const char *struct_type = NULL;
             switch (get_struct_fc(ref))
             {
             case RPC_FC_STRUCT:
@@ -3780,7 +4376,7 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
                  * pass and don't have any memory to free and so don't
                  * need a freeing pass */
                 if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL)
-                    struct_type = "SimpleStruct";
+                    type_str = "SimpleStruct";
                 else if (phase == PHASE_FREE && pass == PASS_RETURN)
                 {
                     print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
@@ -3790,57 +4386,62 @@ static void write_remoting_arg(FILE *file, int indent, const var_t *func, const
                 }
                 break;
             case RPC_FC_PSTRUCT:
-                struct_type = "SimpleStruct";
+                type_str = "SimpleStruct";
                 break;
             case RPC_FC_CSTRUCT:
             case RPC_FC_CPSTRUCT:
-                struct_type = "ConformantStruct";
+                type_str = "ConformantStruct";
                 break;
             case RPC_FC_CVSTRUCT:
-                struct_type = "ConformantVaryingStruct";
+                type_str = "ConformantVaryingStruct";
                 break;
             case RPC_FC_BOGUS_STRUCT:
-                struct_type = "ComplexStruct";
+                type_str = "ComplexStruct";
                 break;
             default:
                 error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, get_struct_fc(ref));
             }
 
-            if (struct_type)
+            if (type_str)
             {
                 if (phase == PHASE_FREE)
-                    struct_type = "Pointer";
+                    type_str = "Pointer";
                 else
                     start_offset = ref->typestring_offset;
-                print_phase_function(file, indent, struct_type, local_var_prefix, phase, var, start_offset);
+                print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
             }
             break;
-        }
         case TGT_UNION:
-        {
-            const char *union_type = NULL;
             if (phase == PHASE_FREE)
-                union_type = "Pointer";
+                type_str = "Pointer";
             else
             {
                 if (type_get_type(ref) == TYPE_UNION)
-                    union_type = "NonEncapsulatedUnion";
+                    type_str = "NonEncapsulatedUnion";
                 else if (type_get_type(ref) == TYPE_ENCAPSULATED_UNION)
-                    union_type = "EncapsulatedUnion";
+                    type_str = "EncapsulatedUnion";
 
                 start_offset = ref->typestring_offset;
             }
 
-            print_phase_function(file, indent, union_type, local_var_prefix,
+            print_phase_function(file, indent, type_str, local_var_prefix,
                                  phase, var, start_offset);
             break;
-        }
+        case TGT_USER_TYPE:
+            if (phase != PHASE_FREE)
+            {
+                type_str = "UserMarshal";
+                start_offset = ref->typestring_offset;
+            }
+            else type_str = "Pointer";
+
+            print_phase_function(file, indent, type_str, local_var_prefix, phase, var, start_offset);
+            break;
         case TGT_STRING:
         case TGT_POINTER:
         case TGT_ARRAY:
         case TGT_RANGE:
         case TGT_IFACE_POINTER:
-        case TGT_USER_TYPE:
         case TGT_CTXT_HANDLE:
         case TGT_CTXT_HANDLE_POINTER:
             print_phase_function(file, indent, "Pointer", local_var_prefix, phase, var, start_offset);
@@ -3892,10 +4493,10 @@ void write_remoting_arguments(FILE *file, int indent, const var_t *func, const c
 }
 
 
-unsigned int get_size_procformatstring_func(const var_t *func)
+unsigned int get_size_procformatstring_func(const type_t *iface, const var_t *func)
 {
     unsigned int offset = 0;
-    write_procformatstring_func( NULL, 0, func, &offset );
+    write_procformatstring_func( NULL, 0, iface, func, &offset, 0 );
     return offset;
 }
 
@@ -3925,7 +4526,7 @@ unsigned int get_size_procformatstring(const statement_list_t *stmts, type_pred_
         {
             const var_t *func = stmt_func->u.var;
             if (!is_local(func->attrs))
-                size += get_size_procformatstring_func( func );
+                size += get_size_procformatstring_func( iface, func );
         }
     }
     return size;
@@ -4030,10 +4631,22 @@ void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char
                 if (type_array_has_conformance(var->type))
                 {
                     unsigned int size;
-                    type_t *type = var->type;
+                    type_t *type;
 
                     fprintf(file, " = NdrAllocate(&__frame->_StubMsg, ");
-                    for ( ;
+                    for (type = var->type;
+                         is_array(type) && type_array_has_conformance(type);
+                         type = type_array_get_element(type))
+                    {
+                        write_expr(file, type_array_get_conformance(type), TRUE,
+                                   TRUE, NULL, NULL, local_var_prefix);
+                        fprintf(file, " * ");
+                    }
+                    size = type_memsize(type);
+                    fprintf(file, "%u);\n", size);
+
+                    print_file(file, indent, "memset(%s%s, 0, ", local_var_prefix, var->name);
+                    for (type = var->type;
                          is_array(type) && type_array_has_conformance(type);
                          type = type_array_get_element(type))
                     {
@@ -4055,12 +4668,15 @@ void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char
                 case TGT_ENUM:
                 case TGT_POINTER:
                 case TGT_RANGE:
+                case TGT_IFACE_POINTER:
                     print_file(file, indent, "%s_W%u = 0;\n", local_var_prefix, i);
                     break;
+                case TGT_USER_TYPE:
+                    print_file(file, indent, "memset(&%s_W%u, 0, sizeof(%s_W%u));\n",
+                               local_var_prefix, i, local_var_prefix, i);
+                    break;
                 case TGT_STRUCT:
                 case TGT_UNION:
-                case TGT_USER_TYPE:
-                case TGT_IFACE_POINTER:
                 case TGT_ARRAY:
                 case TGT_CTXT_HANDLE:
                 case TGT_CTXT_HANDLE_POINTER:
@@ -4083,6 +4699,69 @@ void assign_stub_out_args( FILE *file, int indent, const var_t *func, const char
 }
 
 
+void write_func_param_struct( FILE *file, const type_t *iface, const type_t *func,
+                              const char *var_decl, int add_retval )
+{
+    type_t *rettype = type_function_get_rettype( func );
+    const var_list_t *args = type_get_function_args( func );
+    const var_t *arg;
+    int needs_packing;
+    unsigned int align = 0;
+
+    if (args)
+        LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
+            if (!is_array( arg->type )) type_memsize_and_alignment( arg->type, &align );
+
+    needs_packing = (align > pointer_size);
+
+    if (needs_packing) print_file( file, 0, "#include <pshpack%u.h>\n", pointer_size );
+    print_file(file, 1, "struct _PARAM_STRUCT\n" );
+    print_file(file, 1, "{\n" );
+    if (is_object( iface )) print_file(file, 2, "%s *This;\n", iface->name );
+
+    if (args) LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
+    {
+        print_file(file, 2, "%s", "");
+        write_type_left( file, (type_t *)arg->type, TRUE );
+        if (needs_space_after( arg->type )) fputc( ' ', file );
+        if (is_array( arg->type ) && !type_array_is_decl_as_ptr( arg->type )) fputc( '*', file );
+
+        /* FIXME: should check for large args being passed by pointer */
+        align = 0;
+        if (is_array( arg->type ) || is_ptr( arg->type )) align = pointer_size;
+        else type_memsize_and_alignment( arg->type, &align );
+
+        if (align >= pointer_size)
+            fprintf( file, "%s;\n", arg->name );
+        else
+            fprintf( file, "%s DECLSPEC_ALIGN(%u);\n", arg->name, pointer_size );
+    }
+    if (add_retval && !is_void( rettype ))
+    {
+        print_file(file, 2, "%s", "");
+        write_type_decl( file, rettype, "_RetVal" );
+        if (is_array( rettype ) || is_ptr( rettype ) || type_memsize( rettype ) == pointer_size)
+            fprintf( file, ";\n" );
+        else
+            fprintf( file, " DECLSPEC_ALIGN(%u);\n", pointer_size );
+    }
+    print_file(file, 1, "} %s;\n", var_decl );
+    if (needs_packing) print_file( file, 0, "#include <poppack.h>\n" );
+    print_file( file, 0, "\n" );
+}
+
+void write_pointer_checks( FILE *file, int indent, const var_t *func )
+{
+    const var_list_t *args = type_get_function_args( func->type );
+    const var_t *var;
+
+    if (!args) return;
+
+    LIST_FOR_EACH_ENTRY( var, args, const var_t, entry )
+        if (cant_be_null( var ))
+            print_file( file, indent, "if (!%s) RpcRaiseException(RPC_X_NULL_REF_POINTER);\n", var->name );
+}
+
 int write_expr_eval_routines(FILE *file, const char *iface)
 {
     static const char *var_name = "pS";
@@ -4093,20 +4772,28 @@ int write_expr_eval_routines(FILE *file, const char *iface)
 
     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
     {
-        const char *name = eval->structure->name;
+        const char *name = eval->name;
         result = 1;
 
         print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
-                   iface, name, callback_offset);
+                   eval->iface ? eval->iface->name : iface, name, callback_offset);
         print_file(file, 0, "{\n");
-        print_file(file, 1, "%s", "");
-        write_type_left(file, (type_t *)eval->structure, TRUE);
-        fprintf(file, " *%s = (", var_name);
-        write_type_left(file, (type_t *)eval->structure, TRUE);
-        fprintf(file, " *)(pStubMsg->StackTop - %u);\n", eval->baseoff);
+        if (type_get_type( eval->cont_type ) == TYPE_FUNCTION)
+        {
+            write_func_param_struct( file, eval->iface, eval->cont_type,
+                                     "*pS = (struct _PARAM_STRUCT *)pStubMsg->StackTop", FALSE );
+        }
+        else
+        {
+            print_file(file, 1, "%s", "");
+            write_type_left(file, (type_t *)eval->cont_type, TRUE);
+            fprintf(file, " *%s = (", var_name);
+            write_type_left(file, (type_t *)eval->cont_type, TRUE);
+            fprintf(file, " *)(pStubMsg->StackTop - %u);\n", eval->baseoff);
+        }
         print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
         print_file(file, 1, "pStubMsg->MaxCount = (ULONG_PTR)");
-        write_expr(file, eval->expr, 1, 1, var_name_expr, eval->structure, "");
+        write_expr(file, eval->expr, 1, 1, var_name_expr, eval->cont_type, "");
         fprintf(file, ";\n");
         print_file(file, 0, "}\n\n");
         callback_offset++;
@@ -4125,10 +4812,11 @@ void write_expr_eval_routine_list(FILE *file, const char *iface)
 
     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
     {
-        const char *name = eval->structure->name;
-        print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset);
+        print_file(file, 1, "%s_%sExprEval_%04u,\n",
+                   eval->iface ? eval->iface->name : iface, eval->name, callback_offset);
         callback_offset++;
         list_remove(&eval->entry);
+        free(eval->name);
         free(eval);
     }
 
@@ -4191,6 +4879,65 @@ error:
     error("Invalid endpoint syntax '%s'\n", endpoint->str);
 }
 
+void write_client_call_routine( FILE *file, const type_t *iface, const var_t *func,
+                                const char *prefix, unsigned int proc_offset )
+{
+    type_t *rettype = type_function_get_rettype( func->type );
+    int has_ret = !is_void( rettype );
+    const var_list_t *args = type_get_function_args( func->type );
+    const var_t *arg;
+    int len, needs_params = 0;
+
+    /* we need a param structure if we have more than one arg */
+    if (pointer_size == 4 && args) needs_params = is_object( iface ) || list_count( args ) > 1;
+
+    print_file( file, 0, "{\n");
+    if (needs_params)
+    {
+        if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n" );
+        write_func_param_struct( file, iface, func->type, "__params", FALSE );
+        if (is_object( iface )) print_file( file, 1, "__params.This = This;\n" );
+        if (args)
+            LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
+                print_file( file, 1, "__params.%s = %s;\n", arg->name, arg->name );
+    }
+    else if (has_ret) print_file( file, 1, "%s", "CLIENT_CALL_RETURN _RetVal;\n\n" );
+
+    len = fprintf( file, "    %s%s( ",
+                   has_ret ? "_RetVal = " : "",
+                   get_stub_mode() == MODE_Oif ? "NdrClientCall2" : "NdrClientCall" );
+    fprintf( file, "&%s_StubDesc,", prefix );
+    fprintf( file, "\n%*s&__MIDL_ProcFormatString.Format[%u]", len, "", proc_offset );
+    if (needs_params)
+    {
+        fprintf( file, ",\n%*s&__params", len, "" );
+    }
+    else if (pointer_size == 8)
+    {
+        if (is_object( iface )) fprintf( file, ",\n%*sThis", len, "" );
+        if (args)
+            LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
+                fprintf( file, ",\n%*s%s", len, "", arg->name );
+    }
+    else
+    {
+        if (is_object( iface )) fprintf( file, ",\n%*s&This", len, "" );
+        else if (args)
+        {
+            arg = LIST_ENTRY( list_head(args), const var_t, entry );
+            fprintf( file, ",\n%*s&%s", len, "", arg->name );
+        }
+    }
+    fprintf( file, " );\n" );
+    if (has_ret)
+    {
+        print_file( file, 1, "return (" );
+        write_type_decl_left(file, rettype);
+        fprintf( file, ")%s;\n", pointer_size == 8 ? "_RetVal.Simple" : "*(LONG_PTR *)&_RetVal" );
+    }
+    print_file( file, 0, "}\n\n");
+}
+
 void write_exceptions( FILE *file )
 {
     fprintf( file, "#ifndef USE_COMPILER_EXCEPTIONS\n");