diff --git a/tools/widl/client.c b/tools/widl/client.c index 310a8e4822a..c2af6b9c4f2 100644 --- a/tools/widl/client.c +++ b/tools/widl/client.c @@ -87,30 +87,44 @@ static void print_message_buffer_size(const func_t *func) fprintf(client, " %u", total_size); } - -static int has_out_arg_or_return(const func_t *func) +static void check_pointers(const func_t *func) { var_t *var; - - if (!is_void(func->def->type, NULL)) - return 1; + int pointer_type; if (!func->args) - return 0; + return; var = func->args; while (NEXT_LINK(var)) var = NEXT_LINK(var); while (var) { - if (is_attr(var->attrs, ATTR_OUT)) - return 1; + pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE); + if (!pointer_type) + pointer_type = RPC_FC_RP; + + if (pointer_type == RPC_FC_RP) + { + if (var->ptr_level == 1) + { + print_client("if (!%s)\n", var->name); + print_client("{\n"); + indent++; + print_client("RpcRaiseException(RPC_X_NULL_REF_POINTER);\n"); + indent--; + print_client("}\n\n"); + } + else if (var->ptr_level > 1) + { + error("Pointer level %d not supported!\n", var->ptr_level); + return; + } + } var = PREV_LINK(var); } - return 0; } - static void write_function_stubs(type_t *iface) { const func_t *func = iface->funcs; @@ -177,6 +191,10 @@ static void write_function_stubs(type_t *iface) print_client("RPC_MESSAGE _RpcMessage;\n"); print_client("MIDL_STUB_MESSAGE _StubMsg;\n"); fprintf(client, "\n"); + + /* check pointers */ + check_pointers(func); + print_client("RpcTryFinally\n"); print_client("{\n"); indent++; @@ -206,6 +224,9 @@ static void write_function_stubs(type_t *iface) print_message_buffer_size(func); fprintf(client, ";\n"); + type_offset_func = type_offset; + write_remoting_arguments(client, indent, func, &type_offset_func, PASS_IN, PHASE_BUFFERSIZE); + print_client("NdrGetBuffer(\n"); indent++; print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); diff --git a/tools/widl/header.c b/tools/widl/header.c index 7f262335b6d..3b290d6cff2 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -518,6 +518,28 @@ const var_t* get_explicit_handle_var(const func_t* func) return NULL; } +int has_out_arg_or_return(const 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; +} + /********** INTERFACES **********/ diff --git a/tools/widl/header.h b/tools/widl/header.h index e905ae446eb..bed1357e41b 100644 --- a/tools/widl/header.h +++ b/tools/widl/header.h @@ -44,6 +44,7 @@ extern void write_externdef(const var_t *v); extern void write_library(const char *name, const attr_t *attr); extern void write_user_types(void); extern const var_t* get_explicit_handle_var(const func_t* func); +extern int has_out_arg_or_return(const func_t *func); static inline int is_string_type(const attr_t *attrs, int ptr_level, const expr_t *array) { diff --git a/tools/widl/server.c b/tools/widl/server.c index f2dacf3857b..a7f3a74b5a6 100644 --- a/tools/widl/server.c +++ b/tools/widl/server.c @@ -106,7 +106,7 @@ static void declare_args(const func_t *func) if (!out_attr && !in_attr) in_attr = 1; - if (!in_attr) + if (!in_attr && !is_attr(var->attrs, ATTR_STRING)) { print_server(""); write_type(server, var->type, NULL, var->tname); @@ -130,6 +130,8 @@ static void assign_out_args(const func_t *func) int in_attr, out_attr; int i = 0, sep = 0; var_t *var; + const expr_t *size_is; + int has_size; if (!func->args) return; @@ -138,6 +140,8 @@ static void assign_out_args(const func_t *func) while (NEXT_LINK(var)) var = NEXT_LINK(var); while (var) { + size_is = get_attrp(var->attrs, ATTR_SIZEIS); + has_size = size_is && (size_is->type != EXPR_VOID); in_attr = is_attr(var->attrs, ATTR_IN); out_attr = is_attr(var->attrs, ATTR_OUT); if (!out_attr && !in_attr) @@ -147,7 +151,22 @@ static void assign_out_args(const func_t *func) { print_server(""); write_name(server, var); - fprintf(server, " = &_W%u;\n", i++); + + if (has_size) + { + type_t *type = var->type; + while (type->type == 0 && type->ref) + type = type->ref; + + fprintf(server, " = NdrAllocate(&_StubMsg, "); + write_expr(server, size_is, 1); + fprintf(server, " * %u);\n", get_type_memsize(type)); + } + else + { + fprintf(server, " = &_W%u;\n", i++); + } + sep = 1; } @@ -342,10 +361,14 @@ static void write_function_stubs(type_t *iface) buffer_size += alignment; } - if (buffer_size) + if (has_out_arg_or_return(func)) { fprintf(server, "\n"); - print_server("_StubMsg.BufferLength = %uU;\n", buffer_size); + print_server("_StubMsg.BufferLength = %u;\n", buffer_size); + + type_offset_func = type_offset; + write_remoting_arguments(server, indent, func, &type_offset_func, PASS_OUT, PHASE_BUFFERSIZE); + print_server("_pRpcMessage->BufferLength = _StubMsg.BufferLength;\n"); fprintf(server, "\n"); print_server("_Status = I_RpcGetBuffer(_pRpcMessage);\n"); @@ -358,6 +381,8 @@ static void write_function_stubs(type_t *iface) fprintf(server, "\n"); } + type_offset_func = type_offset; + /* marshall arguments */ write_remoting_arguments(server, indent, func, &type_offset, PASS_OUT, PHASE_MARSHAL); @@ -380,6 +405,11 @@ static void write_function_stubs(type_t *iface) print_server("}\n"); print_server("RpcFinally\n"); print_server("{\n"); + indent++; + + write_remoting_arguments(server, indent, func, &type_offset_func, PASS_OUT, PHASE_FREE); + + indent--; print_server("}\n"); print_server("RpcEndFinally\n"); diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c index e00d838e61f..1d681d9d420 100644 --- a/tools/widl/typegen.c +++ b/tools/widl/typegen.c @@ -576,6 +576,11 @@ static size_t type_memsize(const type_t *t, int ptr_level, const expr_t *array) return size; } +size_t get_type_memsize(const type_t *type) +{ + return type_memsize(type, 0, NULL); +} + static int write_pointers(FILE *file, const attr_t *attrs, const type_t *type, int ptr_level, const expr_t *array, int level, @@ -690,6 +695,13 @@ static size_t write_string_tfs(FILE *file, const attr_t *attrs, const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS); int has_size = size_is && (size_is->type != EXPR_VOID); size_t start_offset = *typestring_offset; + unsigned char flags = 0; + int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE); + if (!pointer_type) + pointer_type = RPC_FC_RP; + + if (!get_attrp(attrs, ATTR_SIZEIS)) + flags |= RPC_FC_P_SIMPLEPOINTER; if ((type->type != RPC_FC_BYTE) && (type->type != RPC_FC_CHAR) && (type->type != RPC_FC_WCHAR)) { @@ -697,6 +709,18 @@ static size_t write_string_tfs(FILE *file, const attr_t *attrs, return start_offset; } + print_file(file, 2,"0x%x, 0x%x, /* %s%s */\n", + pointer_type, flags, + pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"), + (flags & RPC_FC_P_SIMPLEPOINTER) ? " [simple_pointer]" : ""); + *typestring_offset += 2; + + if (!(flags & RPC_FC_P_SIMPLEPOINTER)) + { + print_file(file, 2, "NdrFcShort(0x2);\n"); + *typestring_offset += 2; + } + if (array && array->is_const) { if (array->cval > USHRT_MAX) @@ -1335,13 +1359,30 @@ static unsigned int get_required_buffer_size_type( } if (ptr_level == 0 && type_has_ref(type)) return get_required_buffer_size_type(type->ref, 0 /* FIXME */, array, name, alignment); - if (ptr_level == 1) - return 25; /* FIXME: Only 'in' pointers need this */ return 0; } unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment) { + int in_attr = is_attr(var->attrs, ATTR_IN); + int out_attr = is_attr(var->attrs, ATTR_OUT); + + if (!in_attr && !out_attr) + in_attr = 1; + + if ((!out_attr || in_attr) && !is_attr(var->attrs, ATTR_STRING) && !var->array) + { + if (var->ptr_level > 0 || (var->ptr_level == 0 && type_has_ref(var->type))) + { + type_t *type = var->type; + while (type->type == 0 && type->ref) + type = type->ref; + + if (is_base_type(type->type)) + return 25; + } + } + return get_required_buffer_size_type(var->type, var->ptr_level, var->array, var->name, alignment); } @@ -1365,6 +1406,9 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func, unsigned int *type_offset, enum pass pass, enum remoting_phase phase) { + const expr_t *length_is; + const expr_t *size_is; + int in_attr, out_attr, has_length, has_size, pointer_type; var_t *var; if (!func->args) @@ -1374,9 +1418,17 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func, while (NEXT_LINK(var)) var = NEXT_LINK(var); for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var)) { - int in_attr = is_attr(var->attrs, ATTR_IN); - int out_attr = is_attr(var->attrs, ATTR_OUT); + length_is = get_attrp(var->attrs, ATTR_LENGTHIS); + size_is = get_attrp(var->attrs, ATTR_SIZEIS); + has_length = length_is && (length_is->type != EXPR_VOID); + has_size = (size_is && (size_is->type != EXPR_VOID)) || (var->array && !var->array->is_const); + pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE); + if (!pointer_type) + pointer_type = RPC_FC_RP; + + in_attr = is_attr(var->attrs, ATTR_IN); + out_attr = is_attr(var->attrs, ATTR_OUT); if (!in_attr && !out_attr) in_attr = 1; @@ -1401,17 +1453,42 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func, "NdrNonConformantString%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n", function_from_phase(phase), var->name, *type_offset); else - print_file(file, indent, - "NdrConformantString%s(&_StubMsg, (unsigned char *)%s, &__MIDL_TypeFormatString.Format[%d]);\n", - function_from_phase(phase), var->name, *type_offset); + { + if (size_is && phase != PHASE_UNMARSHAL) + { + print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)"); + write_expr(file, size_is, 1); + fprintf(file, ";\n"); + } + + if (phase == PHASE_FREE) + { + print_file(file, indent, "NdrPointerFree(\n"); + indent++; + print_file(file, indent, "&_StubMsg,\n"); + print_file(file, indent, "(unsigned char *)%s,\n", var->name); + print_file(file, indent, "&__MIDL_TypeFormatString.Format[%d]);\n", + *type_offset); + indent--; + } + else + { + print_file(file, indent, "NdrConformantString%s(\n", function_from_phase(phase)); + indent++; + print_file(file, indent, "(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_file(file, indent, "(unsigned char *)%s,\n", var->name); + print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n", + *type_offset + (has_size ? 4 : 2), + (phase == PHASE_MARSHAL) ? ");" : ","); + if (phase == PHASE_UNMARSHAL) + print_file(file, indent, "(unsigned char)0);\n"); + indent--; + } + } } else if (is_array_type(var->attrs, var->ptr_level, var->array)) { - const expr_t *length_is = get_attrp(var->attrs, ATTR_LENGTHIS); - const expr_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS); const char *array_type; - int has_length = length_is && (length_is->type != EXPR_VOID); - int has_size = (size_is && (size_is->type != EXPR_VOID)) || !var->array->is_const; if (var->array && NEXT_LINK(var->array)) /* multi-dimensional array */ array_type = "ComplexArray"; @@ -1506,31 +1583,34 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func, size = 0; } - print_file(file, indent, "_StubMsg.Buffer += (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n", - alignment - 1, alignment - 1); - - if (phase == PHASE_MARSHAL) + if (phase == PHASE_MARSHAL || phase == PHASE_UNMARSHAL) { - print_file(file, indent, "*("); - write_type(file, var->type, var, var->tname); - fprintf(file, " *)_StubMsg.Buffer = "); - write_name(file, var); - fprintf(file, ";\n"); - } - else if (phase == PHASE_UNMARSHAL) - { - print_file(file, indent, ""); - write_name(file, var); - fprintf(file, " = *("); - write_type(file, var->type, var, var->tname); - fprintf(file, " *)_StubMsg.Buffer;\n"); - } - else - error("write_remoting_arguments: Unimplemented for base types for phase %d\n", phase); + print_file(file, indent, "_StubMsg.Buffer += (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n", + alignment - 1, alignment - 1); - print_file(file, indent, "_StubMsg.Buffer += sizeof("); - write_type(file, var->type, var, var->tname); - fprintf(file, ");\n"); + if (phase == PHASE_MARSHAL) + { + print_file(file, indent, "*("); + write_type(file, var->type, var, var->tname); + fprintf(file, " *)_StubMsg.Buffer = "); + write_name(file, var); + fprintf(file, ";\n"); + } + else if (phase == PHASE_UNMARSHAL) + { + print_file(file, indent, ""); + write_name(file, var); + fprintf(file, " = *("); + write_type(file, var->type, var, var->tname); + fprintf(file, " *)_StubMsg.Buffer;\n"); + } + else + error("write_remoting_arguments: Unimplemented for base types for phase %d\n", phase); + + print_file(file, indent, "_StubMsg.Buffer += sizeof("); + write_type(file, var->type, var, var->tname); + fprintf(file, ");\n"); + } } else if (var->ptr_level == 0) { @@ -1563,10 +1643,6 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func, } else { - int pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE); - if (!pointer_type) - pointer_type = RPC_FC_RP; - if (pointer_type == RPC_FC_RP) { unsigned int size; diff --git a/tools/widl/typegen.h b/tools/widl/typegen.h index 080bdaf234a..61e317cfea3 100644 --- a/tools/widl/typegen.h +++ b/tools/widl/typegen.h @@ -37,6 +37,7 @@ enum remoting_phase void write_procformatstring(FILE *file, type_t *iface); void write_typeformatstring(FILE *file, type_t *iface); +size_t get_type_memsize(const type_t *type); unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment); void write_remoting_arguments(FILE *file, int indent, const func_t *func, unsigned int *type_offset, enum pass pass, enum remoting_phase phase); size_t get_size_procformatstring_var(const var_t *var);