Commit d458a599 authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

widl: Add support for non-basetype return types.

parent a95420a0
......@@ -497,6 +497,12 @@ s_sum_L1_norms(int n, vector_t *vs)
return sum;
}
str_t
s_get_filename(void)
{
return (char *)__FILE__;
}
void
s_stop(void)
{
......@@ -558,6 +564,7 @@ basic_tests(void)
int x;
str_struct_t ss = {string};
wstr_struct_t ws = {wstring};
str_t str;
ok(int_return() == INT_CODE, "RPC int_return\n");
......@@ -652,6 +659,9 @@ basic_tests(void)
ok(sum_bogus(&bogus) == 12, "RPC sum_bogus\n");
check_null(NULL);
str = get_filename();
ok(!strcmp(str, __FILE__), "get_filename() returned %s instead of %s\n", str, __FILE__);
}
static void
......
......@@ -300,5 +300,7 @@ cpp_quote("#endif")
int sum_pcarr2(int n, [size_is(, n)] int **pa);
int sum_L1_norms(int n, [size_is(n)] vector_t *vs);
str_t get_filename(void);
void stop(void);
}
......@@ -139,6 +139,11 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
print_client("RPC_MESSAGE _RpcMessage;\n");
print_client("MIDL_STUB_MESSAGE _StubMsg;\n");
if (!is_void(def->type) && decl_indirect(def->type))
{
print_client("void *_p_%s = &%s;\n",
"_RetVal", "_RetVal");
}
fprintf(client, "\n");
/* check pointers */
......@@ -216,7 +221,13 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
/* unmarshal return value */
if (!is_void(def->type))
print_phase_basetype(client, indent, PHASE_UNMARSHAL, PASS_RETURN, def, "_RetVal");
{
if (decl_indirect(def->type))
print_client("MIDL_memset(&%s, 0, sizeof(%s));\n", "_RetVal", "_RetVal");
else if (is_ptr(def->type) || is_array(def->type))
print_client("%s = 0;\n", "_RetVal");
write_remoting_arguments(client, indent, func, PASS_RETURN, PHASE_UNMARSHAL);
}
/* update proc_offset */
if (func->args)
......
......@@ -272,6 +272,11 @@ static void gen_proxy(type_t *iface, const func_t *cur, int idx,
}
print_proxy( "RPC_MESSAGE _RpcMessage;\n" );
print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" );
if (has_ret) {
if (decl_indirect(def->type))
print_proxy("void *_p_%s = &%s;\n",
"_RetVal", "_RetVal");
}
print_proxy( "\n");
/* FIXME: trace */
......@@ -307,7 +312,13 @@ static void gen_proxy(type_t *iface, const func_t *cur, int idx,
write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_UNMARSHAL);
if (has_ret)
print_phase_basetype(proxy, indent, PHASE_UNMARSHAL, PASS_RETURN, def, "_RetVal");
{
if (decl_indirect(def->type))
print_proxy("MIDL_memset(&%s, 0, sizeof(%s));\n", "_RetVal", "_RetVal");
else if (is_ptr(def->type) || is_array(def->type))
print_proxy("%s = 0;\n", "_RetVal");
write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_UNMARSHAL);
}
indent--;
print_proxy( "}\n");
......
......@@ -209,6 +209,9 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
{
write_remoting_arguments(server, indent, func, PASS_OUT, PHASE_BUFFERSIZE);
if (!is_void(def->type))
write_remoting_arguments(server, indent, func, PASS_RETURN, PHASE_BUFFERSIZE);
print_server("_pRpcMessage->BufferLength = _StubMsg.BufferLength;\n");
fprintf(server, "\n");
print_server("_Status = I_RpcGetBuffer(_pRpcMessage);\n");
......@@ -226,7 +229,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
/* marshall the return value */
if (!is_void(def->type))
print_phase_basetype(server, indent, PHASE_MARSHAL, PASS_RETURN, def, "_RetVal");
write_remoting_arguments(server, indent, func, PASS_RETURN, PHASE_MARSHAL);
indent--;
print_server("}\n");
......@@ -236,6 +239,9 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
write_remoting_arguments(server, indent, func, PASS_OUT, PHASE_FREE);
if (!is_void(def->type))
write_remoting_arguments(server, indent, func, PASS_RETURN, PHASE_FREE);
indent--;
print_server("}\n");
print_server("RpcEndFinally\n");
......
......@@ -325,22 +325,27 @@ void print(FILE *file, int indent, const char *format, va_list va)
}
}
static void write_var_init(FILE *file, int indent, const type_t *t, const char *n)
{
if (decl_indirect(t))
print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n);
else if (is_ptr(t) || is_array(t))
print_file(file, indent, "%s = 0;\n", n);
}
void write_parameters_init(FILE *file, int indent, const func_t *func)
{
const var_t *var;
if (!is_void(func->def->type))
write_var_init(file, indent, func->def->type, "_RetVal");
if (!func->args)
return;
LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
{
const type_t *t = var->type;
const char *n = var->name;
if (decl_indirect(t))
print_file(file, indent, "MIDL_memset(&%s, 0, sizeof %s);\n", n, n);
else if (is_ptr(t) || is_array(t))
print_file(file, indent, "%s = 0;\n", n);
}
write_var_init(file, indent, var->type, var->name);
fprintf(file, "\n");
}
......@@ -2621,239 +2626,200 @@ expr_t *get_size_is_expr(const type_t *t, const char *name)
return x;
}
void write_remoting_arguments(FILE *file, int indent, const func_t *func,
enum pass pass, enum remoting_phase phase)
static void write_remoting_arg(FILE *file, int indent, const func_t *func,
enum pass pass, enum remoting_phase phase,
const var_t *var)
{
int in_attr, out_attr, pointer_type;
const var_t *var;
const type_t *type = var->type;
unsigned char rtype;
size_t start_offset = type->typestring_offset;
if (!func->args)
return;
pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
if (!pointer_type)
pointer_type = RPC_FC_RP;
if (phase == PHASE_BUFFERSIZE)
{
unsigned int size = get_function_buffer_size( func, pass );
print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
}
in_attr = is_attr(var->attrs, ATTR_IN);
out_attr = is_attr(var->attrs, ATTR_OUT);
if (!in_attr && !out_attr)
in_attr = 1;
LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
if (phase == PHASE_FREE)
{
const type_t *type = var->type;
unsigned char rtype;
size_t start_offset = type->typestring_offset;
if (!needs_freeing(var->attrs, type, out_attr))
return;
}
else
switch (pass)
{
case PASS_IN:
if (!in_attr) return;
break;
case PASS_OUT:
if (!out_attr) return;
break;
case PASS_RETURN:
break;
}
pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
if (!pointer_type)
pointer_type = RPC_FC_RP;
rtype = type->type;
in_attr = is_attr(var->attrs, ATTR_IN);
out_attr = is_attr(var->attrs, ATTR_OUT);
if (!in_attr && !out_attr)
in_attr = 1;
if (phase == PHASE_FREE)
if (is_context_handle(type))
{
if (phase == PHASE_MARSHAL)
{
if (pass == PASS_IN)
{
print_file(file, indent, "NdrClientContextMarshall(\n");
print_file(file, indent + 1, "&_StubMsg,\n");
print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name);
print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
}
else
{
print_file(file, indent, "NdrServerContextMarshall(\n");
print_file(file, indent + 1, "&_StubMsg,\n");
print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown);\n", get_context_handle_type_name(var->type));
}
}
else if (phase == PHASE_UNMARSHAL)
{
if (!needs_freeing(var->attrs, type, out_attr))
continue;
if (pass == PASS_OUT)
{
print_file(file, indent, "NdrClientContextUnmarshall(\n");
print_file(file, indent + 1, "&_StubMsg,\n");
print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
print_file(file, indent + 1, "_Handle);\n");
}
else
print_file(file, indent, "%s = NdrServerContextUnmarshall(&_StubMsg);\n", var->name);
}
}
else if (is_user_type(var->type))
{
print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
}
else if (is_string_type(var->attrs, var->type))
{
if (is_array(type) && !is_conformant_array(type))
print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
else
switch (pass)
{
if (type->size_is && is_size_needed_for_phase(phase))
{
case PASS_IN:
if (!in_attr) continue;
break;
case PASS_OUT:
if (!out_attr) continue;
break;
case PASS_RETURN:
break;
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
write_expr(file, type->size_is, 1);
fprintf(file, ";\n");
}
rtype = type->type;
if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
print_phase_function(file, indent, "Pointer", phase, var, start_offset);
else
print_phase_function(file, indent, "ConformantString", phase, var,
start_offset + (type->size_is ? 4 : 2));
}
}
else if (is_array(type))
{
unsigned char tc = type->type;
const char *array_type = "FixedArray";
if (is_context_handle(type))
/* We already have the size_is expression since it's at the
top level, but do checks for multidimensional conformant
arrays. When we handle them, we'll need to extend this
function to return a list, and then we'll actually use
the return value. */
get_size_is_expr(type, var->name);
if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
{
if (phase == PHASE_MARSHAL)
{
if (pass == PASS_IN)
{
print_file(file, indent, "NdrClientContextMarshall(\n");
print_file(file, indent + 1, "&_StubMsg,\n");
print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name);
print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
}
else
{
print_file(file, indent, "NdrServerContextMarshall(\n");
print_file(file, indent + 1, "&_StubMsg,\n");
print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown);\n", get_context_handle_type_name(var->type));
}
}
else if (phase == PHASE_UNMARSHAL)
if (is_size_needed_for_phase(phase))
{
if (pass == PASS_OUT)
{
print_file(file, indent, "NdrClientContextUnmarshall(\n");
print_file(file, indent + 1, "&_StubMsg,\n");
print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
print_file(file, indent + 1, "_Handle);\n");
}
else
print_file(file, indent, "%s = NdrServerContextUnmarshall(&_StubMsg);\n", var->name);
print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
write_expr(file, type->length_is, 1);
fprintf(file, ";\n\n");
}
array_type = "VaryingArray";
}
else if (is_user_type(var->type))
else if (tc == RPC_FC_CARRAY)
{
print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
if (is_size_needed_for_phase(phase))
{
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
write_expr(file, type->size_is, 1);
fprintf(file, ";\n\n");
}
array_type = "ConformantArray";
}
else if (is_string_type(var->attrs, var->type))
else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
{
if (is_array(type) && !is_conformant_array(type))
print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
else
if (is_size_needed_for_phase(phase))
{
if (type->size_is && is_size_needed_for_phase(phase))
if (type->size_is)
{
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
write_expr(file, type->size_is, 1);
fprintf(file, ";\n");
}
if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
print_phase_function(file, indent, "Pointer", phase, var, start_offset);
else
print_phase_function(file, indent, "ConformantString", phase, var,
start_offset + (type->size_is ? 4 : 2));
}
}
else if (is_array(type))
{
unsigned char tc = type->type;
const char *array_type = "FixedArray";
/* We already have the size_is expression since it's at the
top level, but do checks for multidimensional conformant
arrays. When we handle them, we'll need to extend this
function to return a list, and then we'll actually use
the return value. */
get_size_is_expr(type, var->name);
if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
{
if (is_size_needed_for_phase(phase))
if (type->length_is)
{
print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
write_expr(file, type->length_is, 1);
fprintf(file, ";\n\n");
}
array_type = "VaryingArray";
}
else if (tc == RPC_FC_CARRAY)
{
if (is_size_needed_for_phase(phase))
{
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
write_expr(file, type->size_is, 1);
fprintf(file, ";\n\n");
}
array_type = "ConformantArray";
}
else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
{
if (is_size_needed_for_phase(phase))
{
if (type->size_is)
{
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
write_expr(file, type->size_is, 1);
fprintf(file, ";\n");
}
if (type->length_is)
{
print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
write_expr(file, type->length_is, 1);
fprintf(file, ";\n\n");
}
}
array_type = (tc == RPC_FC_BOGUS_ARRAY
? "ComplexArray"
: "ConformantVaryingArray");
}
if (pointer_type != RPC_FC_RP) array_type = "Pointer";
print_phase_function(file, indent, array_type, phase, var, start_offset);
if (phase == PHASE_FREE && type->declarray && pointer_type == RPC_FC_RP)
{
/* these are all unmarshalled by pointing into the buffer on the
* server side */
if (type->type != RPC_FC_SMFARRAY &&
type->type != RPC_FC_LGFARRAY &&
type->type != RPC_FC_CARRAY)
{
print_file(file, indent, "if (%s)\n", var->name);
indent++;
print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
}
}
}
else if (!is_ptr(var->type) && is_base_type(rtype))
{
print_phase_basetype(file, indent, phase, pass, var, var->name);
array_type = (tc == RPC_FC_BOGUS_ARRAY
? "ComplexArray"
: "ConformantVaryingArray");
}
else if (!is_ptr(var->type))
if (pointer_type != RPC_FC_RP) array_type = "Pointer";
print_phase_function(file, indent, array_type, phase, var, start_offset);
if (phase == PHASE_FREE && type->declarray && pointer_type == RPC_FC_RP)
{
switch (rtype)
/* these are all unmarshalled by pointing into the buffer on the
* server side */
if (type->type != RPC_FC_SMFARRAY &&
type->type != RPC_FC_LGFARRAY &&
type->type != RPC_FC_CARRAY)
{
case RPC_FC_STRUCT:
case RPC_FC_PSTRUCT:
print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
break;
case RPC_FC_CSTRUCT:
case RPC_FC_CPSTRUCT:
print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
break;
case RPC_FC_CVSTRUCT:
print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
break;
case RPC_FC_BOGUS_STRUCT:
print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
break;
case RPC_FC_RP:
if (is_base_type( var->type->ref->type ))
{
print_phase_basetype(file, indent, phase, pass, var, var->name);
}
else if (var->type->ref->type == RPC_FC_STRUCT)
{
if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
}
else
{
expr_t *iid;
if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
{
print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
write_expr( file, iid, 1 );
fprintf( file, ";\n\n" );
}
print_phase_function(file, indent, "Pointer", phase, var, start_offset);
}
break;
default:
error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
print_file(file, indent, "if (%s)\n", var->name);
indent++;
print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
}
}
else
}
else if (!is_ptr(var->type) && is_base_type(rtype))
{
print_phase_basetype(file, indent, phase, pass, var, var->name);
}
else if (!is_ptr(var->type))
{
switch (rtype)
{
if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
case RPC_FC_STRUCT:
case RPC_FC_PSTRUCT:
print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
break;
case RPC_FC_CSTRUCT:
case RPC_FC_CPSTRUCT:
print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
break;
case RPC_FC_CVSTRUCT:
print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
break;
case RPC_FC_BOGUS_STRUCT:
print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
break;
case RPC_FC_RP:
if (is_base_type( var->type->ref->type ))
{
print_phase_basetype(file, indent, phase, pass, var, var->name);
}
else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
else if (var->type->ref->type == RPC_FC_STRUCT)
{
if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
......@@ -2861,27 +2827,80 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
else
{
expr_t *iid;
expr_t *sx = get_size_is_expr(type, var->name);
if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
{
print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
write_expr( file, iid, 1 );
fprintf( file, ";\n\n" );
}
else if (sx)
{
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
write_expr(file, sx, 1);
fprintf(file, ";\n\n");
}
if (var->type->ref->type == RPC_FC_IP)
print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
else
print_phase_function(file, indent, "Pointer", phase, var, start_offset);
print_phase_function(file, indent, "Pointer", phase, var, start_offset);
}
break;
default:
error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
}
fprintf(file, "\n");
}
else
{
if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
{
print_phase_basetype(file, indent, phase, pass, var, var->name);
}
else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
{
if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
}
else
{
expr_t *iid;
expr_t *sx = get_size_is_expr(type, var->name);
if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
{
print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
write_expr( file, iid, 1 );
fprintf( file, ";\n\n" );
}
else if (sx)
{
print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
write_expr(file, sx, 1);
fprintf(file, ";\n\n");
}
if (var->type->ref->type == RPC_FC_IP)
print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
else
print_phase_function(file, indent, "Pointer", phase, var, start_offset);
}
}
fprintf(file, "\n");
}
void write_remoting_arguments(FILE *file, int indent, const func_t *func,
enum pass pass, enum remoting_phase phase)
{
if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
{
unsigned int size = get_function_buffer_size( func, pass );
print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
}
if (pass == PASS_RETURN)
{
var_t var;
var = *func->def;
var.name = xstrdup( "_RetVal" );
write_remoting_arg( file, indent, func, pass, phase, &var );
free( var.name );
}
else
{
const var_t *var;
if (!func->args)
return;
LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
write_remoting_arg( file, indent, func, pass, phase, var );
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment