Implement [in], [out] and [in, out] support for pointers to basic types.
Modified: trunk/reactos/tools/widl/ChangeLog
Modified: trunk/reactos/tools/widl/client.c
Modified: trunk/reactos/tools/widl/server.c

Modified: trunk/reactos/tools/widl/ChangeLog
--- trunk/reactos/tools/widl/ChangeLog	2005-03-12 09:40:07 UTC (rev 13965)
+++ trunk/reactos/tools/widl/ChangeLog	2005-03-12 13:23:09 UTC (rev 13966)
@@ -1,5 +1,13 @@
 ChangeLog
 
+2005-03-12 ekohl
+
+   tools/widl/client.c
+   tools/widl/server.c
+
+Implement [in], [out] and [in, out] support for pointers to basic types.
+
+
 2005-03-10 ekohl
 
    tools/widl/client.c

Modified: trunk/reactos/tools/widl/client.c
--- trunk/reactos/tools/widl/client.c	2005-03-12 09:40:07 UTC (rev 13965)
+++ trunk/reactos/tools/widl/client.c	2005-03-12 13:23:09 UTC (rev 13966)
@@ -61,6 +61,7 @@
     func_t *func = iface->funcs;
     var_t *var;
     unsigned int type_offset = 2;
+    int in_attr, out_attr;
 
     print_client("static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
     print_client("{\n");
@@ -79,6 +80,13 @@
             while (NEXT_LINK(var)) var = NEXT_LINK(var);
             while (var)
             {
+                out_attr = is_attr(var->attrs, ATTR_OUT);
+                in_attr = is_attr(var->attrs, ATTR_IN);
+
+                /* set 'in' attribute if neither 'in' nor 'out' is set */
+                if (!out_attr && !in_attr)
+                    in_attr = 1;
+
                 if (var->ptr_level == 0)
                 {
                     if (is_base_type(var->type))
@@ -96,7 +104,12 @@
                 {
                     if (is_base_type(var->type))
                     {
-                        print_client("0x4d,    /* FC_IN_PARAM */\n");
+                        if (in_attr & !out_attr)
+                            print_client("0x4d,    /* FC_IN_PARAM */\n");
+                        else if (!in_attr & out_attr)
+                            print_client("0x51,    /* FC_OUT_PARAM */\n");
+                        else if (in_attr & out_attr)
+                            print_client("0x50,    /* FC_IN_OUT_PARAM */\n");
                         fprintf(client, "#ifndef _ALPHA_\n");
                         print_client("0x01,\n");
                         fprintf(client, "#else\n");
@@ -150,6 +163,7 @@
 {
     func_t *func = iface->funcs;
     var_t *var;
+    int out_attr;
 
     print_client("static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
     print_client("{\n");
@@ -168,6 +182,8 @@
             while (NEXT_LINK(var)) var = NEXT_LINK(var);
             while (var)
             {
+                out_attr = is_attr(var->attrs, ATTR_OUT);
+
                 if (var->ptr_level > 1)
                 {
                     error("Function '%s' argument '%s': Pointer level %d not supported!\n",
@@ -179,7 +195,10 @@
                 {
                     if (is_base_type(var->type))
                     {
-                        print_client("0x11, 0x08,    /* FC_RP [simple_pointer] */\n");
+                        if (out_attr)
+                            print_client("0x11, 0x0c,    /* FC_RP [allocated_on_stack] [simple_pointer] */\n");
+                        else
+                            print_client("0x11, 0x08,    /* FC_RP [simple_pointer] */\n");
                         print_client("0x%02x,          /* FC_<type> */\n", var->type->type);
                         print_client("0x5c,          /* FC_PAD */\n");
                     }
@@ -210,75 +229,80 @@
     int last_size = -1;
     int in_attr;
     int out_attr;
+    int nothing_printed = 1;
     var_t *var;
 
-    if (!func->args)
+    if (func->args)
     {
-        fprintf(client, " 0U");
-        return;
-    }
+        var = func->args;
+        while (NEXT_LINK(var)) var = NEXT_LINK(var);
+        for (; var; var = PREV_LINK(var))
+        {
+            out_attr = is_attr(var->attrs, ATTR_OUT);
+            in_attr = is_attr(var->attrs, ATTR_IN);
 
-    var = func->args;
-    while (NEXT_LINK(var)) var = NEXT_LINK(var);
-    for (; var; var = PREV_LINK(var))
-    {
-        out_attr = is_attr(var->attrs, ATTR_OUT);
-        in_attr = is_attr(var->attrs, ATTR_IN);
+            /* set 'in' attribute if neither 'in' nor 'out' is found */
+            if (!out_attr && !in_attr)
+                in_attr = 1;
 
-        /* set 'in' attribute if neither 'in' nor 'out' is found */
-        if (!out_attr && !in_attr)
-            in_attr = 1;
+            if (!in_attr)
+                continue;
 
-        if (!in_attr)
-            continue;
-
-        alignment = 0;
-        switch (var->type->type)
-        {
-        case RPC_FC_BYTE:
-        case RPC_FC_CHAR:
-        case RPC_FC_SMALL:
-            size = 1;
             alignment = 0;
-            break;
+            switch (var->type->type)
+            {
+            case RPC_FC_BYTE:
+            case RPC_FC_CHAR:
+            case RPC_FC_SMALL:
+                size = 1;
+                alignment = 0;
+                break;
 
-        case RPC_FC_WCHAR:
-        case RPC_FC_USHORT:
-        case RPC_FC_SHORT:
-            size = 2;
-            if (last_size > 0 && last_size < 2)
-                alignment += (2 - last_size);
-            break;
+            case RPC_FC_WCHAR:
+            case RPC_FC_USHORT:
+            case RPC_FC_SHORT:
+                size = 2;
+                if (last_size > 0 && last_size < 2)
+                    alignment += (2 - last_size);
+                break;
 
-        case RPC_FC_ULONG:
-        case RPC_FC_LONG:
-        case RPC_FC_FLOAT:
-            size = 4;
-            if (last_size > 0 && last_size < 4)
-                alignment += (4 - last_size);
-            break;
+            case RPC_FC_ULONG:
+            case RPC_FC_LONG:
+            case RPC_FC_FLOAT:
+                size = 4;
+                if (last_size > 0 && last_size < 4)
+                    alignment += (4 - last_size);
+                break;
 
-        case RPC_FC_HYPER:
-        case RPC_FC_DOUBLE:
-            size = 8;
-            if (last_size > 0 && last_size < 4)
-                alignment += (4 - last_size);
-            break;
+            case RPC_FC_HYPER:
+            case RPC_FC_DOUBLE:
+                size = 8;
+                if (last_size > 0 && last_size < 4)
+                    alignment += (4 - last_size);
+                break;
 
-        case RPC_FC_IGNORE:
-            size = 0;
-            break;
+            case RPC_FC_IGNORE:
+                size = 0;
+                break;
 
-        default:
-            error("Unknown/unsupported type!");
-        }
+            default:
+                error("Unknown/unsupported type!");
+                return;
+            }
 
-        if (last_size != -1)
-            fprintf(client, " +");
-        fprintf(client, " %dU", (size == 0) ? 0 : size + alignment);
+            if (last_size != -1)
+                fprintf(client, " +");
+            fprintf(client, " %dU", (size == 0) ? 0 : size + alignment);
+            nothing_printed = 0;
 
-        last_size = size;
+            last_size = size;
+        }
     }
+
+    if (nothing_printed)
+    {
+        fprintf(client, " 0U");
+    }
 }
 
 
@@ -376,6 +400,137 @@
 }
 
 
+static void unmarshall_out_arguments(func_t *func)
+{
+    unsigned int alignment;
+    unsigned int size;
+    unsigned int last_size = 0;
+    int out_attr;
+    var_t *var;
+    var_t *def;
+
+    def = func->def;
+
+    /* unmarshall the out arguments */
+    if (func->args)
+    {
+        var = func->args;
+        while (NEXT_LINK(var)) var = NEXT_LINK(var);
+        for (; var; var = PREV_LINK(var))
+        {
+            out_attr = is_attr(var->attrs, ATTR_OUT);
+            if (!out_attr)
+                continue;
+
+            if (var->ptr_level > 1)
+            {
+                error("Function '%s' argument '%s': Pointer level %d not supported!\n",
+                      func->def->name, var->name, var->ptr_level);
+                return;
+            }
+
+            alignment = 0;
+            switch (var->type->type)
+            {
+            case RPC_FC_BYTE:
+            case RPC_FC_CHAR:
+            case RPC_FC_SMALL:
+                size = 1;
+                alignment = 0;
+                break;
+
+            case RPC_FC_WCHAR:
+            case RPC_FC_USHORT:
+            case RPC_FC_SHORT:
+                size = 2;
+                if (last_size > 0 && last_size < 2)
+                    alignment = (2 - last_size);
+                break;
+
+            case RPC_FC_ULONG:
+            case RPC_FC_LONG:
+            case RPC_FC_FLOAT:
+                size = 4;
+                if (last_size > 0 && last_size < 4)
+                    alignment = (4 - last_size);
+                break;
+
+            case RPC_FC_HYPER:
+            case RPC_FC_DOUBLE:
+                size = 8;
+                if (last_size > 0 && last_size < 4)
+                    alignment = (4 - last_size);
+                break;
+
+            case RPC_FC_IGNORE:
+                size = 0;
+                break;
+
+            default:
+                error("Unknown/unsupported type!");
+            }
+
+            if (size != 0)
+            {
+                if (var->ptr_level == 1)
+                {
+                    fprintf(client, "\n");
+                    if (alignment != 0)
+                        print_client("_StubMsg.Buffer += %u;\n", alignment);
+
+                    print_client("*");
+                    write_name(client, var);
+                    fprintf(client, " = *((");
+                    write_type(client, var->type, NULL, var->tname);
+                    fprintf(client, " __RPC_FAR *)_StubMsg.Buffer)++;\n");
+                }
+
+                last_size = size;
+            }
+        }
+    }
+
+    /* unmarshall return value */
+    if (!is_void(def->type, NULL))
+    {
+        alignment = 0;
+        switch (def->type->type)
+        {
+        case RPC_FC_BYTE:
+        case RPC_FC_CHAR:
+        case RPC_FC_SMALL:
+        case RPC_FC_WCHAR:
+        case RPC_FC_USHORT:
+        case RPC_FC_SHORT:
+        case RPC_FC_ULONG:
+        case RPC_FC_LONG:
+        case RPC_FC_FLOAT:
+            size = 4;
+            if (last_size > 0 && last_size < 4)
+                alignment = (4 - last_size);
+            break;
+
+        case RPC_FC_HYPER:
+        case RPC_FC_DOUBLE:
+            size = 8;
+            if (last_size > 0 && last_size < 4)
+                alignment = (4 - last_size);
+            break;
+
+        default:
+            error("Unknown/unsupported type!");
+        }
+
+       fprintf(client, "\n");
+       if (alignment != 0)
+           print_client("_StubMsg.Buffer += %u;\n", alignment);
+       print_client("_RetVal = *((");
+       write_type(client, def->type, def, def->tname);
+       fprintf(client, " __RPC_FAR *)_StubMsg.Buffer)++;\n");
+    }
+}
+
+
 static void check_pointers(func_t *func)
 {
     var_t *var;
@@ -408,6 +563,30 @@
 }
 
 
+static int use_return_buffer(func_t *func)
+{
+    var_t *var;
+
+    if (!is_void(func->def->type, NULL))
+        return 1;
+
+    if (!func->args)
+        return 0;
+
+    var = func->args;
+    while (NEXT_LINK(var)) var = NEXT_LINK(var);
+    while (var)
+    {
+        if (is_attr(var->attrs, ATTR_OUT))
+            return 1;
+
+        var = PREV_LINK(var);
+    }
+
+    return 0;
+}
+
+
 static void write_function_stubs(type_t *iface)
 {
     char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
@@ -523,11 +702,10 @@
         print_client("(unsigned char __RPC_FAR *)_StubMsg.Buffer);\n");
         indent--;
 
-        /* convert data representation */
-        if (!is_void(def->type, NULL))
+        if (use_return_buffer(func))
         {
+            /* convert data representation */
             fprintf(client, "\n");
-
             print_client("if ((_RpcMessage.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n");
             indent++;
             print_client("NdrConvert(\n");
@@ -535,11 +713,9 @@
             print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
             print_client("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset);
             indent -= 2;
-            fprintf(client, "\n");
 
-            print_client("_RetVal = *((");
-            write_type(client, def->type, def, def->tname);
-            fprintf(client, " __RPC_FAR *)_StubMsg.Buffer)++;\n");
+            /* unmarshal out arguments */
+            unmarshall_out_arguments(func);
         }
 
         /* update proc_offset */

Modified: trunk/reactos/tools/widl/server.c
--- trunk/reactos/tools/widl/server.c	2005-03-12 09:40:07 UTC (rev 13965)
+++ trunk/reactos/tools/widl/server.c	2005-03-12 13:23:09 UTC (rev 13966)
@@ -66,6 +66,7 @@
     func_t *func = iface->funcs;
     var_t *var;
     unsigned int type_offset = 2;
+    int in_attr, out_attr;
 
     print_server("static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
     print_server("{\n");
@@ -84,6 +85,13 @@
             while (NEXT_LINK(var)) var = NEXT_LINK(var);
             while (var)
             {
+                out_attr = is_attr(var->attrs, ATTR_OUT);
+                in_attr = is_attr(var->attrs, ATTR_IN);
+
+                /* set 'in' attribute if neither 'in' nor 'out' is set */
+                if (!out_attr && !in_attr)
+                    in_attr = 1;
+
                 if (var->ptr_level == 0)
                 {
                     if (is_base_type(var->type))
@@ -101,7 +109,12 @@
                 {
                     if (is_base_type(var->type))
                     {
-                        print_server("0x4d,    /* FC_IN_PARAM */\n");
+                        if (in_attr & !out_attr)
+                            print_server("0x4d,    /* FC_IN_PARAM */\n");
+                        else if (!in_attr & out_attr)
+                            print_server("0x51,    /* FC_OUT_PARAM */\n");
+                        else if (in_attr & out_attr)
+                            print_server("0x50,    /* FC_IN_OUT_PARAM */\n");
                         fprintf(server, "#ifndef _ALPHA_\n");
                         print_server("0x01,\n");
                         fprintf(server, "#else\n");
@@ -155,6 +168,7 @@
 {
     func_t *func = iface->funcs;
     var_t *var;
+    int out_attr;
 
     print_server("static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
     print_server("{\n");
@@ -173,6 +187,8 @@
             while (NEXT_LINK(var)) var = NEXT_LINK(var);
             while (var)
             {
+                out_attr = is_attr(var->attrs, ATTR_OUT);
+
                 if (var->ptr_level > 1)
                 {
                     error("Function '%s' argument '%s': Pointer level %d not supported!\n",
@@ -184,7 +200,10 @@
                 {
                     if (is_base_type(var->type))
                     {
-                        print_server("0x11, 0x08,    /* FC_RP [simple_pointer] */\n");
+                        if (out_attr)
+                            print_server("0x11, 0x0c,    /* FC_RP [allocated_on_stack] [simple_pointer] */\n");
+                        else
+                            print_server("0x11, 0x08,    /* FC_RP [simple_pointer] */\n");
                         print_server("0x%02x,          /* FC_<type> */\n", var->type->type);
                         print_server("0x5c,          /* FC_PAD */\n");
                     }
@@ -208,10 +227,75 @@
 }
 
 
-unsigned int get_required_buffer_size(type_t *type)
+static void print_message_buffer_size(func_t *func)
 {
-    switch(type->type)
+    unsigned int alignment;
+    int size;
+    int last_size = -1;
+    int in_attr;
+    int out_attr;
+    var_t *var;
+
+    if (func->args)
     {
+        var = func->args;
+        while (NEXT_LINK(var)) var = NEXT_LINK(var);
+        for (; var; var = PREV_LINK(var))
+        {
+            out_attr = is_attr(var->attrs, ATTR_OUT);
+            if (!out_attr)
+                continue;
+
+            alignment = 0;
+            switch (var->type->type)
+            {
+            case RPC_FC_BYTE:
+            case RPC_FC_CHAR:
+            case RPC_FC_SMALL:
+                size = 1;
+                alignment = 0;
+                break;
+
+            case RPC_FC_WCHAR:
+            case RPC_FC_USHORT:
+            case RPC_FC_SHORT:
+                size = 2;
+                if (last_size > 0 && last_size < 2)
+                    alignment += (2 - last_size);
+                break;
+
+            case RPC_FC_ULONG:
+            case RPC_FC_LONG:
+            case RPC_FC_FLOAT:
+                size = 4;
+                if (last_size > 0 && last_size < 4)
+                    alignment += (4 - last_size);
+                break;
+
+            case RPC_FC_HYPER:
+            case RPC_FC_DOUBLE:
+                size = 8;
+                if (last_size > 0 && last_size < 4)
+                    alignment += (4 - last_size);
+                break;
+
+            default:
+                error("Unknown/unsupported type!");
+            }
+
+            if (last_size != -1)
+                fprintf(server, " +");
+            fprintf(server, " %dU", (size == 0) ? 0 : size + alignment);
+
+            last_size = size;
+        }
+    }
+
+    /* return value size */
+    if (!is_void(func->def->type, NULL))
+    {
+        switch(func->def->type->type)
+        {
         case RPC_FC_BYTE:
         case RPC_FC_SMALL:
         case RPC_FC_CHAR:
@@ -221,18 +305,27 @@
         case RPC_FC_ULONG:
         case RPC_FC_LONG:
         case RPC_FC_FLOAT:
-            return 4;
+            size = 4;
+            if (last_size > 0 && last_size < 4)
+                alignment += (4 - last_size);
+            break;
 
         case RPC_FC_HYPER:
         case RPC_FC_DOUBLE:
-            return 8;
+            size = 8;
+            if (last_size > 0 && last_size < 4)
+                alignment += (4 - last_size);
+            break;
 
-        case RPC_FC_IGNORE:
-            return 0;
+        default:
+            error("Unknown/unsupported type: %s\n", func->def->type->name);
+            return;
+        }
 
-        default:
-            error("Unknown/unsupported type: %s\n", type->name);
-            return 0;
+        if (last_size != -1)
+            fprintf(server, " +");
+
+        fprintf(server, " %dU", (size == 0) ? 0 : size + alignment);
     }
 }
 
@@ -266,20 +359,32 @@
 }
 
 
-static void unmarshall_arguments(func_t *func)
+static void unmarshall_in_arguments(func_t *func)
 {
     unsigned int alignment;
     unsigned int size;
     unsigned int last_size = 0;
     var_t *var;
+    int in_attr;
+    int out_attr;
 
     if (!func->args)
         return;
 
     var = func->args;
     while (NEXT_LINK(var)) var = NEXT_LINK(var);
-    while (var)
+    for (; var; var = PREV_LINK(var))
     {
+        out_attr = is_attr(var->attrs, ATTR_OUT);
+        in_attr = is_attr(var->attrs, ATTR_IN);
+
+        /* set 'in' attribute if neither 'in' nor 'out' is set */
+        if (!out_attr && !in_attr)
+            in_attr = 1;
+
+        if (!in_attr)
+            continue;
+
         alignment = 0;
         switch (var->type->type)
         {
@@ -355,9 +460,160 @@
 
             last_size = size;
         }
+    }
+}
 
+
+static void marshall_out_arguments(func_t *func)
+{
+    unsigned int alignment = 0;
+    unsigned int size = 0;
+    unsigned int last_size = 0;
+    var_t *var;
+    var_t *def;
+    int out_attr;
+
+    def = func->def;
+
+    /* marshall the out arguments */
+    if (func->args)
+    {
+        var = func->args;
+        while (NEXT_LINK(var)) var = NEXT_LINK(var);
+        for (; var; var = PREV_LINK(var))
+        {
+            out_attr = is_attr(var->attrs, ATTR_OUT);
+            if (!out_attr)
+                continue;
+
+            alignment = 0;
+            switch (var->type->type)
+            {
+            case RPC_FC_BYTE:
+            case RPC_FC_CHAR:
+            case RPC_FC_SMALL:
+                size = 1;
+                alignment = 0;
+                break;
+
+            case RPC_FC_WCHAR:
+            case RPC_FC_USHORT:
+            case RPC_FC_SHORT:
+                size = 2;
+                if (last_size != 0 && last_size < 2)
+                    alignment = (2 - last_size);
+                break;
+
+            case RPC_FC_ULONG:
+            case RPC_FC_LONG:
+            case RPC_FC_FLOAT:
+                size = 4;
+                if (last_size != 0 && last_size < 4)
+                    alignment = (4 - last_size);
+                break;
+
+            case RPC_FC_HYPER:
+            case RPC_FC_DOUBLE:
+                size = 8;
+                if (last_size != 0 && last_size < 4)
+                    alignment = (4 - last_size);
+                break;
+
+            case RPC_FC_IGNORE:
+                size = 0;
+                break;
+
+            default:
+                error("Unknown/unsupported type!");
+            }
+
+            if (size != 0)
+            {
+                if (alignment != 0)
+                    print_server("_StubMsg.Buffer += %u;\n", alignment);
+
+                if (var->ptr_level == 1)
+                {
+                    fprintf(server, "\n");
+                    print_server("*((");
+                    write_type(server, var->type, NULL, var->tname);
+                    fprintf(server, " __RPC_FAR *)_StubMsg.Buffer)++ = *");
+                    write_name(server, var);
+                    fprintf(server, ";\n");
+                }
+                else
+                {
+                    error("Pointer level %d is not supported!\n", var->ptr_level);
+                    return;
+                }
+
+                last_size = size;
+            }
+        }
+    }
+
+    /* marshall the return value */
+    if (!is_void(def->type, NULL))
+    {
+        alignment = 0;
+        switch (def->type->type)
+        {
+        case RPC_FC_BYTE:
+        case RPC_FC_CHAR:
+        case RPC_FC_SMALL:
+        case RPC_FC_WCHAR:
+        case RPC_FC_USHORT:
+        case RPC_FC_SHORT:
+        case RPC_FC_ULONG:
+        case RPC_FC_LONG:
+        case RPC_FC_FLOAT:
+            size = 4;
+            if (last_size != 0 && last_size < 4)
+                alignment = (4 - last_size);
+            break;
+
+        case RPC_FC_HYPER:
+        case RPC_FC_DOUBLE:
+            size = 8;
+            if (last_size != 0 && last_size < 4)
+                alignment = (4 - last_size);
+            break;
+
+        default:
+            error("Unknown/unsupported type!");
+        }
+
+        fprintf(server, "\n");
+        if (alignment != 0)
+            print_server("_StubMsg.Buffer += %u;\n", alignment);
+        print_server("*((");
+        write_type(server, def->type, def, def->tname);
+        fprintf(server, " __RPC_FAR *)_StubMsg.Buffer)++ = _RetVal;\n");
+    }
+}
+
+
+static int use_return_buffer(func_t *func)
+{
+    var_t *var;
+
+    if (!is_void(func->def->type, NULL))
+        return 1;
+
+    if (!func->args)
+        return 0;
+
+    var = func->args;
+    while (NEXT_LINK(var)) var = NEXT_LINK(var);
+    while (var)
+    {
+        if (is_attr(var->attrs, ATTR_OUT))
+            return 1;
+
         var = PREV_LINK(var);
     }
+
+    return 0;
 }
 
 
@@ -368,6 +624,9 @@
     var_t *var;
     var_t* explicit_handle_var;
     unsigned int proc_offset = 0;
+    unsigned int i;
+    int in_attr;
+    int out_attr;
 
     while (NEXT_LINK(func)) func = NEXT_LINK(func);
     while (func)
@@ -416,10 +675,23 @@
         /* declare arguments */
         if (func->args)
         {
+            i = 0;
             var = func->args;
             while (NEXT_LINK(var)) var = NEXT_LINK(var);
             while (var)
             {
+                in_attr = is_attr(var->attrs, ATTR_IN);
+                out_attr = is_attr(var->attrs, ATTR_OUT);
+                if (!out_attr && !in_attr)
+                    in_attr = 1;
+                if (!in_attr)
+                {
+                    print_server("");
+                    write_type(server, var->type, NULL, var->tname);
+                    fprintf(server, " _W%u;\n", i);
+                    i++;
+                }
+
                 print_server("");
                 write_type(server, var->type, var, var->tname);
                 fprintf(server, " ");
@@ -470,7 +742,7 @@
             indent -= 2;
             fprintf(server, "\n");
 
-            unmarshall_arguments(func);
+            unmarshall_in_arguments(func);
         }
 
         print_server("if (_StubMsg.Buffer > _StubMsg.BufferEnd)\n");
@@ -490,7 +762,33 @@
         print_server("RpcEndExcept\n");
         fprintf(server, "\n");
 
+        /* assign out arguments */
+        if (func->args)
+        {
+            i = 0;
+            var = func->args;
+            while (NEXT_LINK(var)) var = NEXT_LINK(var);
+            while (var)
+            {
+                in_attr = is_attr(var->attrs, ATTR_IN);
+                out_attr = is_attr(var->attrs, ATTR_OUT);
+                if (!out_attr && !in_attr)
+                    in_attr = 1;
+                if (!in_attr)
+                {
+                    print_server("");
+                    write_name(server, var);
+                    fprintf(server, " = &_W%u;\n", i);
+                    i++;
+                }
 
+                var = PREV_LINK(var);
+            }
+
+            if (i)
+                fprintf(server, "\n");
+        }
+
         /* Call the real server function */
         if (!is_void(def->type, NULL))
             print_server("_RetVal = ");
@@ -524,11 +822,13 @@
             fprintf(server, "();\n");
         }
 
-        /* marshall the return value */
-        if (!is_void(def->type, NULL))
+        /* allocate and fill the return message buffer */
+        if (use_return_buffer(func))
         {
             fprintf(server, "\n");
-            print_server("_StubMsg.BufferLength = %uU;\n", get_required_buffer_size(def->type));
+            print_server("_StubMsg.BufferLength =");
+            print_message_buffer_size(func);
+            fprintf(server, ";\n");
             print_server("_pRpcMessage->BufferLength = _StubMsg.BufferLength;\n");
             fprintf(server, "\n");
             print_server("_Status = I_RpcGetBuffer(_pRpcMessage);\n");
@@ -538,11 +838,9 @@
             indent--;
             fprintf(server, "\n");
             print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)_pRpcMessage->Buffer;\n");
-            fprintf(server, "\n");
 
-            print_server("*((");
-            write_type(server, def->type, def, def->tname);
-            fprintf(server, " __RPC_FAR *)_StubMsg.Buffer)++ = _RetVal;\n");
+            /* marshall the out arguments */
+            marshall_out_arguments(func);
         }
 
         indent--;